├── 2048 ├── .ocp-indent ├── doc │ ├── api.odocl │ └── style.css ├── tests │ ├── test_local.ml │ ├── test.mli │ └── board_utils.ml ├── .merlin ├── src │ ├── local.ml │ ├── main.mli │ ├── anim.mli │ ├── render.mli │ ├── anim.ml │ ├── utils.mli │ ├── utils.ml │ ├── 2048.html │ ├── main.ml │ ├── g2048.mli │ └── render.ml ├── myocamlbuild.ml ├── _tags ├── README.md ├── COPYING ├── build ├── useri │ ├── useri.ml │ ├── useri_backend.ml │ ├── useri_jsoo.ml │ ├── useri_base.mli │ └── useri_jsoo.mli └── support │ └── reload-browser ├── images ├── 2048.png ├── you-win.png └── game-over.png ├── .gitignore ├── static ├── base │ ├── images │ │ └── ipynblogo.png │ └── js │ │ ├── namespace.js │ │ ├── events.js │ │ ├── page.js │ │ └── dialog.js ├── custom │ ├── iocamljsnblogo.png │ ├── custom.css │ └── custom.js ├── components │ ├── jquery-ui │ │ └── themes │ │ │ └── smoothness │ │ │ └── images │ │ │ ├── animated-overlay.gif │ │ │ ├── ui-icons_222222_256x240.png │ │ │ ├── ui-icons_2e83ff_256x240.png │ │ │ ├── ui-icons_454545_256x240.png │ │ │ ├── ui-icons_888888_256x240.png │ │ │ ├── ui-icons_cd0a0a_256x240.png │ │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ │ │ ├── ui-bg_flat_75_ffffff_40x100.png │ │ │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ │ ├── ui-bg_glass_75_dadada_1x400.png │ │ │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ │ │ ├── ui-bg_glass_95_fef1ec_1x400.png │ │ │ └── ui-bg_highlight-soft_75_cccccc_1x100.png │ ├── font-awesome │ │ └── build │ │ │ └── assets │ │ │ └── font-awesome │ │ │ └── font │ │ │ └── fontawesome-webfont.woff │ └── codemirror │ │ ├── addon │ │ ├── mode │ │ │ ├── loadmode.js │ │ │ ├── overlay.js │ │ │ └── multiplex.js │ │ ├── edit │ │ │ └── matchbrackets.js │ │ └── comment │ │ │ └── comment.js │ │ ├── mode │ │ ├── gfm │ │ │ └── gfm.js │ │ └── htmlmixed │ │ │ └── htmlmixed.js │ │ └── lib │ │ └── codemirror.css ├── tree │ ├── css │ │ └── override.css │ └── js │ │ ├── main.js │ │ └── clusterlist.js ├── notebook │ ├── js │ │ ├── codemirror-ipython.js │ │ ├── layoutmanager.js │ │ ├── celltoolbarpresets │ │ │ ├── slideshow.js │ │ │ └── default.js │ │ ├── config.js │ │ ├── notificationwidget.js │ │ ├── contexthint.js │ │ ├── quickhelp.js │ │ ├── toolbar.js │ │ ├── main.js │ │ ├── savewidget.js │ │ ├── pager.js │ │ └── maintoolbar.js │ └── css │ │ └── override.css ├── auth │ └── js │ │ └── loginwidget.js └── dateformat │ └── date.format.js ├── profile └── static │ └── custom │ ├── iocamljsnblogo.png │ ├── custom.css │ └── custom.js ├── unix.js ├── docker ├── kernel.json ├── README.md └── Dockerfile ├── README.md ├── Makefile ├── notebooks └── Modules.ipynb ├── task.md └── index.html /2048/.ocp-indent: -------------------------------------------------------------------------------- 1 | strict_with=always,match_clause=4,strict_else=never -------------------------------------------------------------------------------- /2048/doc/api.odocl: -------------------------------------------------------------------------------- 1 | G2048 2 | Utils 3 | Test 4 | Render 5 | Anim 6 | Useri 7 | Useri_jsoo -------------------------------------------------------------------------------- /2048/tests/test_local.ml: -------------------------------------------------------------------------------- 1 | module M = Test.Make(G2048.Default) 2 | 3 | let _ = M.run () 4 | -------------------------------------------------------------------------------- /images/2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/images/2048.png -------------------------------------------------------------------------------- /images/you-win.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/images/you-win.png -------------------------------------------------------------------------------- /images/game-over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/images/game-over.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build artefacts 2 | _build/ 3 | *.native 4 | *.byte 5 | 6 | # Files generated by emacs 7 | *~ 8 | -------------------------------------------------------------------------------- /static/base/images/ipynblogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/base/images/ipynblogo.png -------------------------------------------------------------------------------- /static/custom/iocamljsnblogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/custom/iocamljsnblogo.png -------------------------------------------------------------------------------- /profile/static/custom/iocamljsnblogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/profile/static/custom/iocamljsnblogo.png -------------------------------------------------------------------------------- /unix.js: -------------------------------------------------------------------------------- 1 | //Provides: unix_gethostname 2 | //Requires: caml_create_string 3 | function unix_gethostname() { return caml_create_string(8) } 4 | -------------------------------------------------------------------------------- /2048/.merlin: -------------------------------------------------------------------------------- 1 | PKG gg 2 | PKG vg 3 | PKG react 4 | PKG js_of_ocaml 5 | PKG ounit 6 | PKG qcheck 7 | B _build/src 8 | B _build/tests 9 | B _build/useri 10 | S src 11 | S tests 12 | S useri -------------------------------------------------------------------------------- /static/components/jquery-ui/themes/smoothness/images/animated-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/jquery-ui/themes/smoothness/images/animated-overlay.gif -------------------------------------------------------------------------------- /static/components/jquery-ui/themes/smoothness/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/jquery-ui/themes/smoothness/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /static/components/jquery-ui/themes/smoothness/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/jquery-ui/themes/smoothness/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /static/components/jquery-ui/themes/smoothness/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/jquery-ui/themes/smoothness/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /static/components/jquery-ui/themes/smoothness/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/jquery-ui/themes/smoothness/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /static/components/jquery-ui/themes/smoothness/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/jquery-ui/themes/smoothness/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /static/components/jquery-ui/themes/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/jquery-ui/themes/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /static/components/jquery-ui/themes/smoothness/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/jquery-ui/themes/smoothness/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /static/components/jquery-ui/themes/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/jquery-ui/themes/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /static/components/jquery-ui/themes/smoothness/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/jquery-ui/themes/smoothness/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /static/components/jquery-ui/themes/smoothness/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/jquery-ui/themes/smoothness/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /static/components/jquery-ui/themes/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/jquery-ui/themes/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /static/components/jquery-ui/themes/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/jquery-ui/themes/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /static/components/font-awesome/build/assets/font-awesome/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/font-awesome/build/assets/font-awesome/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /static/components/jquery-ui/themes/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ocamllabs/2048-tutorial/HEAD/static/components/jquery-ui/themes/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /2048/src/local.ml: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2014 Daniel C. Bünzli. 3 | * 4 | * This file is distributed under the terms of the BSD2 License. 5 | * See the file COPYING for details. 6 | *) 7 | 8 | module M = Main.Make(G2048.Default) 9 | 10 | let () = M.start () 11 | -------------------------------------------------------------------------------- /2048/myocamlbuild.ml: -------------------------------------------------------------------------------- 1 | open Ocamlbuild_plugin 2 | 3 | let () = 4 | dispatch begin fun d -> 5 | Ocamlbuild_js_of_ocaml.dispatcher d; 6 | match d with 7 | | After_rules -> 8 | flag ["js_of_ocaml"; "weak_js"] (A "+weak.js"); 9 | | _ -> () 10 | end 11 | -------------------------------------------------------------------------------- /docker/kernel.json: -------------------------------------------------------------------------------- 1 | { 2 | "display_name": "OCaml", 3 | "language": "ocaml", 4 | "argv": [ 5 | "/root/.opam/system/bin/iocaml.top", 6 | "-log", 7 | "/root/iocaml.log", 8 | "-object-info", 9 | "-completion", 10 | "-connection-file", 11 | "{connection_file}" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /2048/src/main.mli: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2014 Daniel C. Bünzli. 3 | * 4 | * This file is distributed under the terms of the BSD2 License. 5 | * See the file COPYING for details. 6 | *) 7 | 8 | module Make (S: G2048.Solution): sig 9 | 10 | val start: unit -> unit 11 | (** Start the game *) 12 | 13 | end 14 | -------------------------------------------------------------------------------- /static/tree/css/override.css: -------------------------------------------------------------------------------- 1 | /*This file contains any manual css for this page that needs to override the global styles. 2 | This is only required when different pages style the same element differently. This is just 3 | a hack to deal with our current css styles and no new styling should be added in this file.*/ 4 | 5 | #ipython-main-app { 6 | margin: 30px auto 0px auto; 7 | } 8 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | Run [Jupyter](http://jupyter.org/) notebook with 2 | [IOCaml](https://github.com/andrewray/iocaml/). This container is useful to run 3 | the notebooks included in this project. 4 | 5 | ## Build 6 | 7 | docker build --force-rm=true -t iocaml . 8 | 9 | ## Run 10 | 11 | docker run -it -v /abspath/to/folder/with/notebooks:/root/notebooks -p 8888:8888 oh-my-ocaml 12 | -------------------------------------------------------------------------------- /2048/_tags: -------------------------------------------------------------------------------- 1 | <**/*.{ml,mli}> : bin_annot, annot, debug 2 | 3 | : include 4 | : package(vg), package(vg.htmlc), package(react), package(js_of_ocaml) 5 | : weak_js 6 | : package(js_of_ocaml.syntax), syntax(camlp4o) 7 | 8 | : include 9 | : package(gg), package(react) 10 | : package(js_of_ocaml), package(js_of_ocaml.syntax), \ 11 | syntax(camlp4o) 12 | 13 | : include 14 | : package(oUnit), package(qcheck) 15 | -------------------------------------------------------------------------------- /2048/src/anim.mli: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2014 Daniel C. Bünzli. 3 | * 4 | * This file is distributed under the terms of the BSD2 License. 5 | * See the file COPYING for details. 6 | *) 7 | 8 | (** Animation curves. *) 9 | 10 | val ease_in_out : ?a:float -> float -> float 11 | (** [ease_in_out ~a t] is the value of an ease in and out curve at 12 | time [t]. Maps unit intervals to unit intervals. [a] can be used 13 | to control the stiffness of the curve. *) 14 | 15 | val tri : float -> float 16 | (** [tri t] is a triangle (tent) curve at time [t]. Maps the unit interval 17 | to a triangle whose maximum is at [0.5]. The height of the triangle 18 | is [1.], the base at [0.]. *) 19 | -------------------------------------------------------------------------------- /static/notebook/js/codemirror-ipython.js: -------------------------------------------------------------------------------- 1 | // IPython mode is just a slightly altered Python Mode with `?` beeing a extra 2 | // single operator. Here we define `ipython` mode in the require `python` 3 | // callback to auto-load python mode, which is more likely not the best things 4 | // to do, but at least the simple one for now. 5 | 6 | CodeMirror.requireMode('python',function(){ 7 | 8 | CodeMirror.defineMode("ipython", function(conf, parserConf) { 9 | 10 | parserConf.singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!\\?]"); 11 | parserConf.name = 'python' 12 | return CodeMirror.getMode(conf, parserConf); 13 | }, 'python'); 14 | 15 | CodeMirror.defineMIME("text/x-ipython", "ipython"); 16 | }) 17 | -------------------------------------------------------------------------------- /2048/README.md: -------------------------------------------------------------------------------- 1 | 2 | This directory is structured as follows. 3 | 4 | * `src` has the source files of the game. 5 | * `tests` has tests for the game logic. 6 | * `doc` has support for generating the project's documentation. 7 | * `useri` has a copy of the `js_of_ocaml` backend of `useri`. 8 | * `support` some support files for developping the project. 9 | 10 | To build the project use the `build` script. It supports the following 11 | targets: 12 | 13 | ``` 14 | ./build # builds the app, the tests and the docs 15 | ./build app [-b] # builds the web app and reloads it in the browser (-b) 16 | ./build test # builds and runs the tests 17 | ./build doc [-b] # builds project's documentation and reloads browser (-b) 18 | ./build clean # cleans the project 19 | ``` 20 | -------------------------------------------------------------------------------- /static/custom/custom.css: -------------------------------------------------------------------------------- 1 | *, *:before, *:after { -moz-box-sizing: border-box; 2 | -webkit-box-sizing: border-box; 3 | box-sizing: border-box; 4 | margin: 0em; 5 | padding: 0em;} 6 | html { font-size: 1em; 7 | height:100%; width:100%; 8 | background-color: #faf8ef; } 9 | 10 | body { width:100%; height:100%; 11 | font-size: 1rem; 12 | font-family: Arial; 13 | font-weight: 300; 14 | line-height: 1.3125rem; 15 | padding: 2.6rem; } 16 | 17 | h1 { font-weight: 300; font-size: 2rem; 18 | color:#776e65; line-height:2.2rem; 19 | padding-bottom:1.3rem; 20 | text-transform: uppercase; } 21 | 22 | canvas { width:30rem; height:30rem; 23 | outline:none; } 24 | -------------------------------------------------------------------------------- /profile/static/custom/custom.css: -------------------------------------------------------------------------------- 1 | *, *:before, *:after { -moz-box-sizing: border-box; 2 | -webkit-box-sizing: border-box; 3 | box-sizing: border-box; 4 | margin: 0em; 5 | padding: 0em;} 6 | html { font-size: 1em; 7 | height:100%; width:100%; 8 | background-color: #faf8ef; } 9 | 10 | body { width:100%; height:100%; 11 | font-size: 1rem; 12 | font-family: Arial; 13 | font-weight: 300; 14 | line-height: 1.3125rem; 15 | padding: 2.6rem; } 16 | 17 | h1 { font-weight: 300; font-size: 2rem; 18 | color:#776e65; line-height:2.2rem; 19 | padding-bottom:1.3rem; 20 | text-transform: uppercase; } 21 | 22 | canvas { width:30rem; height:30rem; 23 | outline:none; } 24 | -------------------------------------------------------------------------------- /2048/src/render.mli: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2014 Daniel C. Bünzli. 3 | * 4 | * This file is distributed under the terms of the BSD2 License. 5 | * See the file COPYING for details. 6 | *) 7 | 8 | (** 2048 game board renderer *) 9 | 10 | (** {1 Rendering boards} *) 11 | 12 | module Make (S: G2048.Solution): sig 13 | 14 | val image_of_board : G2048.board -> Vg.image 15 | (** [image_of_board board] is an image from [board]. *) 16 | 17 | val animate_board : float -> G2048.move option -> G2048.board -> Vg.image 18 | (** [animate_board t move board] is the image of the animation at time 19 | [t] of the move [move] that yielded [board]. If [t] is [0.] we 20 | have a still rendering of the previous board if [t] is [1.] we 21 | have a still rendering of the new board. Also overlays game over 22 | or winning conditions. *) 23 | 24 | end 25 | -------------------------------------------------------------------------------- /2048/src/anim.ml: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2014 Daniel C. Bünzli. 3 | * 4 | * This file is distributed under the terms of the BSD2 License. 5 | * See the file COPYING for details. 6 | *) 7 | 8 | open Gg 9 | 10 | (* Ease in out, adapted from http://www.flong.com/texts/code/shapers_exp/ *) 11 | 12 | let d_eps = 0.00001 13 | let d_min_a = 0.0 +. d_eps 14 | let d_max_a = 1.0 -. d_eps 15 | 16 | let double_exp_sigmoid a t = 17 | let a = Float.clamp ~min:d_min_a ~max:d_max_a a in 18 | let exp = 1.0 /. (1.0 -. a) in 19 | if t <= 0. then 0. else 20 | if t >= 1. then 1. else 21 | if t <= 0.5 then 0.5 *. ((2.0 *. t) ** exp) else 22 | 1.0 -. 0.5 *. ((2.0 *. (1.0 -. t)) ** exp) 23 | 24 | let ease_in_out ?(a = 0.426) t = double_exp_sigmoid a t 25 | 26 | (* Triangle around 0.5 *) 27 | 28 | let tri t = 29 | if t <= 0. then 0. else 30 | if t >= 1. then 0. else 31 | 1. -. abs_float (2. *. t -. 1.) 32 | -------------------------------------------------------------------------------- /static/base/js/namespace.js: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // Copyright (C) 2008-2011 The IPython Development Team 3 | // 4 | // Distributed under the terms of the BSD License. The full license is in 5 | // the file COPYING, distributed as part of this software. 6 | //---------------------------------------------------------------------------- 7 | 8 | var IPython = IPython || {}; 9 | 10 | IPython.namespace = function (ns_string) { 11 | var parts = ns_string.split('.'), 12 | parent = IPython, 13 | i; 14 | 15 | // String redundant leading global 16 | if (parts[0] === "IPython") { 17 | parts = parts.slice(1); 18 | } 19 | 20 | for (i=0; i 'a list list 11 | (** Transpose a matrix. For instance: 12 | 13 | {[ 14 | [ [ 1; 2]; 15 | [ 3; 4]; ] 16 | ]} 17 | 18 | becomes: 19 | 20 | {[ 21 | [ [ 1; 3]; 22 | [ 2; 4]; ] 23 | ]} 24 | *) 25 | 26 | val replace_one : ('a -> 'a option) -> 'a list -> 'a list option 27 | (** [replace_one f l] replace the first element [e] in [l] such that 28 | [f e] is not [None]. The new value is [y] if [f x = Some y]. *) 29 | 30 | (** / **) 31 | 32 | val fold_listlisti : ('a -> int * int -> 'b -> 'a) -> 'a -> 'b list list -> 'a 33 | val listlist_dims : 'a list list -> int * int 34 | val replace_at : int -> ('a -> 'a) -> 'a list -> 'a list 35 | (** [replace_at i f row] replaces the [i]th element of [row] with the results of 36 | applying [f] to that element. *) 37 | -------------------------------------------------------------------------------- /static/notebook/css/override.css: -------------------------------------------------------------------------------- 1 | /*This file contains any manual css for this page that needs to override the global styles. 2 | This is only required when different pages style the same element differently. This is just 3 | a hack to deal with our current css styles and no new styling should be added in this file.*/ 4 | 5 | #ipython-main-app { 6 | position: relative; 7 | font-size: 110%; 8 | } 9 | 10 | *, *:before, *:after { 11 | -moz-box-sizing: border-box; 12 | -webkit-box-sizing: border-box; 13 | box-sizing: border-box; 14 | margin: 0em; 15 | padding: 0em;} 16 | html { 17 | font-size: 1em; 18 | height:100%; width:100%; 19 | background-color: #faf8ef; } 20 | 21 | body { 22 | width:100%; height:100%; 23 | font-size: 1rem; 24 | font-family: Arial; 25 | font-weight: 300; 26 | line-height: 1.3125rem; 27 | padding: 2.6rem; } 28 | 29 | h1 { 30 | font-weight: 300; font-size: 2rem; 31 | color:#776e65; line-height:2.2rem; 32 | padding-bottom:1.3rem; 33 | text-transform: uppercase; } 34 | 35 | canvas { 36 | width:30rem; height:30rem; 37 | outline:none; } 38 | -------------------------------------------------------------------------------- /2048/src/utils.ml: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2014 Jeremy Yallop. 3 | * 4 | * This file is distributed under the terms of the BSD2 License. 5 | * See the file COPYING for details. 6 | *) 7 | 8 | (* (This is partial.) *) 9 | let rec transpose = function 10 | | [] -> [] 11 | | [] :: _ -> [] 12 | | x -> List.(map hd x :: transpose (map tl x)) 13 | 14 | let fold_listlisti f acc ll = 15 | let col y (x, acc) square = (x + 1, f acc (x, y) square) in 16 | let row (y, acc) row = (y + 1, snd (List.fold_left (col y) (0, acc) row)) in 17 | snd (List.fold_left row (0, acc) (List.rev ll)) 18 | 19 | let listlist_dims ll = 20 | match ll with 21 | | [] -> (0, 0) 22 | | r :: _ -> (List.length r, List.length ll) 23 | 24 | let rec replace_at n f l = 25 | match n, l with 26 | _, [] -> [] 27 | | 0, x :: xs -> f x :: xs 28 | | n, x :: xs -> x :: replace_at (n - 1) f xs 29 | 30 | let rec replace_one p l = match l with 31 | | [] -> None 32 | | x :: xs -> 33 | begin match p x with 34 | | Some y -> Some (y :: xs) 35 | | None -> 36 | begin match replace_one p xs with 37 | | None -> None 38 | | Some ys -> Some (x :: ys) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /static/base/js/events.js: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // Copyright (C) 2008-2011 The IPython Development Team 3 | // 4 | // Distributed under the terms of the BSD License. The full license is in 5 | // the file COPYING, distributed as part of this software. 6 | //---------------------------------------------------------------------------- 7 | 8 | //============================================================================ 9 | // Events 10 | //============================================================================ 11 | 12 | // Give us an object to bind all events to. This object should be created 13 | // before all other objects so it exists when others register event handlers. 14 | // To trigger an event handler: 15 | // $([IPython.events]).trigger('event.Namespace'); 16 | // To handle it: 17 | // $([IPython.events]).on('event.Namespace',function () {}); 18 | 19 | var IPython = (function (IPython) { 20 | 21 | var utils = IPython.utils; 22 | 23 | var Events = function () {}; 24 | 25 | IPython.Events = Events; 26 | IPython.events = new Events(); 27 | 28 | return IPython; 29 | 30 | }(IPython)); 31 | 32 | -------------------------------------------------------------------------------- /2048/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Jeremy Yallop and Daniel C. Bünzli 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 14 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 15 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 16 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 17 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 19 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 21 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 22 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /2048/build: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | OCAMLBUILD=${OCAMLBUILD:="ocamlbuild -classic-display \ 6 | -use-ocamlfind \ 7 | -plugin-tag package(js_of_ocaml.ocamlbuild)"} 8 | 9 | OCAMLDOCFLAGS=${OCAMLDOCFLAGS:="-docflags -colorize-code,-charset,utf-8"} 10 | RELOAD_BROWSER=${RELOAD_BROWSER="./support/reload-browser"} 11 | 12 | action () 13 | { 14 | case $1 in 15 | default) 16 | action app 17 | action test 18 | ;; 19 | app) 20 | shift 21 | $OCAMLBUILD -no-links local.js 2048.html 22 | if [ "$1" = "-b" ]; then 23 | $RELOAD_BROWSER "file://`pwd`/_build/src/2048.html" 24 | fi 25 | ;; 26 | test) 27 | $OCAMLBUILD test.cmo test_local.native 28 | ./test_local.native 29 | ;; 30 | doc) 31 | shift 32 | $OCAMLBUILD -no-links $OCAMLDOCFLAGS doc/api.docdir/index.html 33 | cp doc/style.css _build/doc/api.docdir/ 34 | if [ "$1" = "-b" ]; then 35 | $RELOAD_BROWSER "file://`pwd`/_build/doc/api.docdir/" 36 | fi 37 | ;; 38 | clean) 39 | $OCAMLBUILD -clean ;; 40 | *) 41 | $OCAMLBUILD $* ;; 42 | esac 43 | } 44 | 45 | if [ $# -eq 0 ]; 46 | then action default ; 47 | else action $*; fi 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | An implementation of [2048][twentyfortyeight] in OCaml, designed for 2 | use in tutorials. 3 | 4 | [Click here for the instructions][task] 5 | 6 | ## Prerequisites 7 | 8 | * [Gg][gg], basic types for computer graphics 9 | * [Vg][vg], vector graphics 10 | * [React][react], functional reactive programming 11 | * [Useri][useri], (bundled) user input as React signals and events 12 | * [js_of_ocaml][js_of_ocaml], OCaml byte code to JavaScript compiler 13 | * [ounit][ounit] (for the tests) 14 | * [qcheck][qcheck] (for the tests) 15 | 16 | ## Previously used at 17 | 18 | * [CUFP 2014][cufp-2014] 19 | * [Functional Conf 2014][fuconf-2014] 20 | * [FOSDEM 2015][fosdem-2015] 21 | * [CUFP 2015][cufp-2015] 22 | 23 | [twentyfortyeight]: http://gabrielecirulli.github.io/2048/ 24 | [ounit]: http://ounit.forge.ocamlcore.org/ 25 | [qcheck]: http://cedeela.fr/quickcheck-for-ocaml.html 26 | [gg]: http://erratique.ch/software/gg 27 | [vg]: http://erratique.ch/software/vg 28 | [react]: http://erratique.ch/software/react 29 | [useri]: http://erratique.ch/software/useri 30 | [js_of_ocaml]: http://ocsigen.org/js_of_ocaml/ 31 | [task]: task.md 32 | [cufp-2014]: http://cufp.org/2014/t7-leo-white-introduction-to-ocaml.html 33 | [cufp-2015]: http://cufp.org/2015/t1-mindy-preston-intro-ocaml.html 34 | [fuconf-2014]: http://functionalconf.com/2014/schedule.html 35 | [fuconf-2014-notebook]: http://gazagnaire.org/fuconf14/ 36 | [fosdem-2015]: http://nymote.org/blog/2015/fosdem-unikernel-demo/ 37 | -------------------------------------------------------------------------------- /2048/tests/test.mli: -------------------------------------------------------------------------------- 1 | (* 2 | * Copyright (c) 2014 Jeremy Yallop. 3 | * 4 | * This file is distributed under the terms of the BSD2 License. 5 | * See the file COPYING for details. 6 | *) 7 | 8 | (** Tests *) 9 | 10 | (** {1 Types} *) 11 | 12 | type is_board_winning = G2048.board -> bool 13 | type shift_board = G2048.move -> G2048.board -> G2048.board 14 | type insert_square = G2048.square -> G2048.board -> G2048.board option 15 | type is_game_over = G2048.board -> bool 16 | 17 | (** {1 Winning boards} *) 18 | val test_is_board_winning: is_board_winning -> unit 19 | 20 | (** {2 Shift boards} *) 21 | 22 | val test_is_board_winning_more: shift_board -> is_board_winning -> unit 23 | val test_shift_empty: shift_board -> unit 24 | val test_shift_empty_squares: shift_board -> unit 25 | val test_shift_coalesce: shift_board -> unit 26 | val test_shifts: shift_board -> unit 27 | val test_shift_board_fixpoint: shift_board -> unit 28 | 29 | (** {1 Square inserts} *) 30 | 31 | val test_insert_row_completely_empty: insert_square -> unit 32 | val test_insert_row_partially_empty: insert_square -> unit 33 | val test_insert_row_full: insert_square -> unit 34 | val test_insert_last_square: insert_square -> unit 35 | val test_add: insert_square -> unit 36 | val test_add_to_full: insert_square -> unit 37 | val test_insert: insert_square -> unit 38 | 39 | (** {1 Game over} *) 40 | 41 | val test_game_over: is_game_over -> unit 42 | 43 | module Make (S: G2048.Solution): sig 44 | val run: unit -> OUnit.test_results 45 | end 46 | -------------------------------------------------------------------------------- /2048/src/2048.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 9 | 35 | 2048 36 | 37 |
38 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /static/auth/js/loginwidget.js: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // Copyright (C) 2008-2011 The IPython Development Team 3 | // 4 | // Distributed under the terms of the BSD License. The full license is in 5 | // the file COPYING, distributed as part of this software. 6 | //---------------------------------------------------------------------------- 7 | 8 | //============================================================================ 9 | // Login button 10 | //============================================================================ 11 | 12 | var IPython = (function (IPython) { 13 | 14 | var LoginWidget = function (selector, options) { 15 | var options = options || {}; 16 | this.base_url = options.baseProjectUrl || $('body').data('baseProjectUrl') ; 17 | this.selector = selector; 18 | if (this.selector !== undefined) { 19 | this.element = $(selector); 20 | this.style(); 21 | this.bind_events(); 22 | } 23 | }; 24 | 25 | LoginWidget.prototype.style = function () { 26 | this.element.find("button").addClass("btn btn-small"); 27 | }; 28 | 29 | 30 | LoginWidget.prototype.bind_events = function () { 31 | var that = this; 32 | this.element.find("button#logout").click(function () { 33 | window.location = that.base_url+"logout"; 34 | }); 35 | this.element.find("button#login").click(function () { 36 | window.location = that.base_url+"login"; 37 | }); 38 | }; 39 | 40 | // Set module variables 41 | IPython.LoginWidget = LoginWidget; 42 | 43 | return IPython; 44 | 45 | }(IPython)); 46 | -------------------------------------------------------------------------------- /static/base/js/page.js: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // Copyright (C) 2008-2011 The IPython Development Team 3 | // 4 | // Distributed under the terms of the BSD License. The full license is in 5 | // the file COPYING, distributed as part of this software. 6 | //---------------------------------------------------------------------------- 7 | 8 | //============================================================================ 9 | // Global header/site setup. 10 | //============================================================================ 11 | 12 | var IPython = (function (IPython) { 13 | 14 | var Page = function () { 15 | this.style(); 16 | this.bind_events(); 17 | }; 18 | 19 | Page.prototype.style = function () { 20 | $('div#header').addClass('border-box-sizing'); 21 | $('div#site').addClass('border-box-sizing'); 22 | }; 23 | 24 | 25 | Page.prototype.bind_events = function () { 26 | }; 27 | 28 | 29 | Page.prototype.show = function () { 30 | // The header and site divs start out hidden to prevent FLOUC. 31 | // Main scripts should call this method after styling everything. 32 | this.show_header(); 33 | this.show_site(); 34 | }; 35 | 36 | 37 | Page.prototype.show_header = function () { 38 | // The header and site divs start out hidden to prevent FLOUC. 39 | // Main scripts should call this method after styling everything. 40 | $('div#header').css('display','block'); 41 | }; 42 | 43 | 44 | Page.prototype.show_site = function () { 45 | // The header and site divs start out hidden to prevent FLOUC. 46 | // Main scripts should call this method after styling everything. 47 | $('div#site').css('display','block'); 48 | }; 49 | 50 | 51 | IPython.Page = Page; 52 | 53 | return IPython; 54 | 55 | }(IPython)); 56 | -------------------------------------------------------------------------------- /static/components/codemirror/addon/mode/loadmode.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js"; 3 | 4 | var loading = {}; 5 | function splitCallback(cont, n) { 6 | var countDown = n; 7 | return function() { if (--countDown == 0) cont(); }; 8 | } 9 | function ensureDeps(mode, cont) { 10 | var deps = CodeMirror.modes[mode].dependencies; 11 | if (!deps) return cont(); 12 | var missing = []; 13 | for (var i = 0; i < deps.length; ++i) { 14 | if (!CodeMirror.modes.hasOwnProperty(deps[i])) 15 | missing.push(deps[i]); 16 | } 17 | if (!missing.length) return cont(); 18 | var split = splitCallback(cont, missing.length); 19 | for (var i = 0; i < missing.length; ++i) 20 | CodeMirror.requireMode(missing[i], split); 21 | } 22 | 23 | CodeMirror.requireMode = function(mode, cont) { 24 | if (typeof mode != "string") mode = mode.name; 25 | if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont); 26 | if (loading.hasOwnProperty(mode)) return loading[mode].push(cont); 27 | 28 | var script = document.createElement("script"); 29 | script.src = CodeMirror.modeURL.replace(/%N/g, mode); 30 | var others = document.getElementsByTagName("script")[0]; 31 | others.parentNode.insertBefore(script, others); 32 | var list = loading[mode] = [cont]; 33 | var count = 0, poll = setInterval(function() { 34 | if (++count > 100) return clearInterval(poll); 35 | if (CodeMirror.modes.hasOwnProperty(mode)) { 36 | clearInterval(poll); 37 | loading[mode] = null; 38 | ensureDeps(mode, function() { 39 | for (var i = 0; i < list.length; ++i) list[i](); 40 | }); 41 | } 42 | }, 200); 43 | }; 44 | 45 | CodeMirror.autoLoadMode = function(instance, mode) { 46 | if (!CodeMirror.modes.hasOwnProperty(mode)) 47 | CodeMirror.requireMode(mode, function() { 48 | instance.setOption("mode", instance.getOption("mode")); 49 | }); 50 | }; 51 | }()); 52 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:vivid 2 | 3 | RUN apt-get update -y \ 4 | && apt-get install -y --no-install-recommends software-properties-common \ 5 | && add-apt-repository -y ppa:avsm/ppa \ 6 | && add-apt-repository -y ppa:chris-lea/zeromq \ 7 | && add-apt-repository -y ppa:fkrull/deadsnakes \ 8 | && apt-get update -y \ 9 | && apt-get install -y \ 10 | ocaml \ 11 | ocaml-native-compilers \ 12 | camlp4-extra \ 13 | opam \ 14 | make \ 15 | m4 \ 16 | libgmp-dev \ 17 | libffi-dev \ 18 | libzmq3-dev \ 19 | python3.5 \ 20 | build-essential \ 21 | python3.5-dev \ 22 | python3-pip \ 23 | && rm -rf /var/lib/apt/lists/* 24 | 25 | RUN pip3 install --upgrade jupyter 26 | RUN opam init --auto-setup --build-doc 27 | RUN opam install --build-doc --yes depext batteries 28 | RUN apt-get update 29 | RUN apt-get install pkg-config 30 | RUN opam install --build-doc --yes --deps-only iocaml 31 | RUN opam upgrade 32 | 33 | # TODO: check that your opam is at least 1.2.0 34 | 35 | ENV PATH=$PATH:/root/.opam/system/bin 36 | RUN git clone -b fixes_for_jupyter https://github.com/signalpillar/iocaml.git \ 37 | && cd iocaml \ 38 | && eval `opam config env` \ 39 | && opam remove iocaml-kernel \ 40 | && opam install ocp-index \ 41 | && make install \ 42 | && ipython kernelspec install --name iocaml-kernel /root/.opam/system/lib/iocaml-kernel/ \ 43 | && ipython kernelspec list \ 44 | && touch /root/keyfile \ 45 | && mkdir /root/notebooks 46 | 47 | COPY kernel.json /usr/local/share/jupyter/kernels/iocaml-kernel/kernel.json 48 | 49 | ENV OCAML_TOPLEVEL_PATH=/root/.opam/system/lib/toplevel 50 | CMD eval `opam config env` \ 51 | && OCAMLRUNPARAM=b \ 52 | && ipython notebook \ 53 | --debug \ 54 | --ip=0.0.0.0 \ 55 | --no-browser \ 56 | --Session.keyfile=/root/keyfile \ 57 | --notebook-dir=/root/notebooks 58 | -------------------------------------------------------------------------------- /2048/useri/useri.ml: -------------------------------------------------------------------------------- 1 | (*--------------------------------------------------------------------------- 2 | Copyright (c) 2014 Daniel C. Bünzli. All rights reserved. 3 | Distributed under the BSD3 license, see license at the end of the file. 4 | %%NAME%% release %%VERSION%% 5 | ---------------------------------------------------------------------------*) 6 | 7 | include Useri_backend 8 | 9 | (*--------------------------------------------------------------------------- 10 | Copyright (c) 2014 Daniel C. Bünzli. 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions 15 | are met: 16 | 17 | 1. Redistributions of source code must retain the above copyright 18 | notice, this list of conditions and the following disclaimer. 19 | 20 | 2. Redistributions in binary form must reproduce the above 21 | copyright notice, this list of conditions and the following 22 | disclaimer in the documentation and/or other materials provided 23 | with the distribution. 24 | 25 | 3. Neither the name of Daniel C. Bünzli nor the names of 26 | contributors may be used to endorse or promote products derived 27 | from this software without specific prior written permission. 28 | 29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | ---------------------------------------------------------------------------*) 41 | -------------------------------------------------------------------------------- /2048/useri/useri_backend.ml: -------------------------------------------------------------------------------- 1 | (*--------------------------------------------------------------------------- 2 | Copyright (c) 2014 Daniel C. Bünzli. All rights reserved. 3 | Distributed under the BSD3 license, see license at the end of the file. 4 | %%NAME%% release %%VERSION%% 5 | ---------------------------------------------------------------------------*) 6 | 7 | include Useri_backend_jsoo 8 | 9 | (*--------------------------------------------------------------------------- 10 | Copyright (c) 2014 Daniel C. Bünzli. 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions 15 | are met: 16 | 17 | 1. Redistributions of source code must retain the above copyright 18 | notice, this list of conditions and the following disclaimer. 19 | 20 | 2. Redistributions in binary form must reproduce the above 21 | copyright notice, this list of conditions and the following 22 | disclaimer in the documentation and/or other materials provided 23 | with the distribution. 24 | 25 | 3. Neither the name of Daniel C. Bünzli nor the names of 26 | contributors may be used to endorse or promote products derived 27 | from this software without specific prior written permission. 28 | 29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | ---------------------------------------------------------------------------*) 41 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all run clean doc 2 | 3 | IOCAML = $(shell opam config var iocamljs-kernel:lib) 4 | STATIC = static/services/kernels/js/kernel.2048.js 5 | PROFILE = profile/static/services/kernels/js/kernel.js 6 | DOC = doc/index.html 7 | FILES = static notebooks doc index.html basics.html adt.html modules.html 8 | 9 | all: 10 | @echo "Run './build' in the '2048/' directory to compile the project." 11 | 12 | doc: $(DOC) 13 | @ 14 | 15 | $(STATIC) $(PROFILE): 16 | cd 2048 && ./build 17 | jsoo_mktop -verbose \ 18 | -dont-export-unit gc \ 19 | -export-package react \ 20 | -export-package gg \ 21 | -export-package vg.htmlc \ 22 | -export-package js_of_ocaml \ 23 | -export-package lwt \ 24 | -export-package iocamljs-kernel \ 25 | -export-package qcheck \ 26 | -export-package ounit \ 27 | -export-unit useri \ 28 | -export-unit useri_jsoo \ 29 | -export-unit utils \ 30 | -export-unit anim \ 31 | -export-unit g2048 \ 32 | -export-unit main \ 33 | -export-unit test \ 34 | -jsopt +weak.js -jsopt +toplevel.js -jsopt unix.js \ 35 | -jsopt -I -jsopt ./2048/_build/useri \ 36 | -jsopt -I -jsopt ./2048/_build/src \ 37 | -jsopt -I -jsopt ./2048/_build/tests \ 38 | ./2048/_build/src/utils.cmo \ 39 | ./2048/_build/useri/useri_base.cmo \ 40 | ./2048/_build/useri/useri_backend_jsoo.cmo \ 41 | ./2048/_build/useri/useri_backend.cmo \ 42 | ./2048/_build/useri/useri.cmo \ 43 | ./2048/_build/useri/useri_jsoo.cmo \ 44 | ./2048/_build/src/g2048.cmo \ 45 | ./2048/_build/src/anim.cmo \ 46 | ./2048/_build/src/render.cmo \ 47 | ./2048/_build/src/main.cmo \ 48 | ./2048/_build/tests/board_utils.cmo \ 49 | ./2048/_build/tests/test.cmo \ 50 | -o iocaml.byte 51 | mkdir -p $(shell dirname $(PROFILE)) 52 | mkdir -p $(shell dirname $(STATIC)) 53 | cat *.cmis.js $(IOCAML)/kernel.js iocaml.js > $(PROFILE) 54 | cp $(PROFILE) $(STATIC) 55 | 56 | run: $(PROFILE) $(STATIC) 57 | iocaml -static profile notebooks 58 | 59 | $(DOC): 60 | cd 2048 && ./build doc 61 | 62 | clean: 63 | cd 2048 && ./build clean 64 | rm -f *.cmis.js *~ $(PROFILE) $(STATIC) iocaml.byte $(DOC) 65 | 66 | update: $(PROFILE) $(STATIC) $(DOC) 67 | rsync -avL -e "ssh $(PORT)" $(FILES) $(DEST) 68 | 69 | -include Makefile.private 70 | -------------------------------------------------------------------------------- /2048/useri/useri_jsoo.ml: -------------------------------------------------------------------------------- 1 | (*--------------------------------------------------------------------------- 2 | Copyright (c) 2014 Daniel C. Bünzli. All rights reserved. 3 | Distributed under the BSD3 license, see license at the end of the file. 4 | %%NAME%% release %%VERSION%% 5 | ---------------------------------------------------------------------------*) 6 | 7 | module Touch = Useri_backend_jsoo.Touch 8 | module Key = Useri_backend_jsoo.Key 9 | module Drop = Useri_backend_jsoo.Drop 10 | module Surface = Useri_backend_jsoo.Surface 11 | 12 | (*--------------------------------------------------------------------------- 13 | Copyright (c) 2014 Daniel C. Bünzli. 14 | All rights reserved. 15 | 16 | Redistribution and use in source and binary forms, with or without 17 | modification, are permitted provided that the following conditions 18 | are met: 19 | 20 | 1. Redistributions of source code must retain the above copyright 21 | notice, this list of conditions and the following disclaimer. 22 | 23 | 2. Redistributions in binary form must reproduce the above 24 | copyright notice, this list of conditions and the following 25 | disclaimer in the documentation and/or other materials provided 26 | with the distribution. 27 | 28 | 3. Neither the name of Daniel C. Bünzli nor the names of 29 | contributors may be used to endorse or promote products derived 30 | from this software without specific prior written permission. 31 | 32 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 35 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 37 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 38 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 39 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 40 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 41 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 42 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 43 | ---------------------------------------------------------------------------*) 44 | -------------------------------------------------------------------------------- /static/components/codemirror/addon/mode/overlay.js: -------------------------------------------------------------------------------- 1 | // Utility function that allows modes to be combined. The mode given 2 | // as the base argument takes care of most of the normal mode 3 | // functionality, but a second (typically simple) mode is used, which 4 | // can override the style of text. Both modes get to parse all of the 5 | // text, but when both assign a non-null style to a piece of code, the 6 | // overlay wins, unless the combine argument was true, in which case 7 | // the styles are combined. 8 | 9 | // overlayParser is the old, deprecated name 10 | CodeMirror.overlayMode = CodeMirror.overlayParser = function(base, overlay, combine) { 11 | return { 12 | startState: function() { 13 | return { 14 | base: CodeMirror.startState(base), 15 | overlay: CodeMirror.startState(overlay), 16 | basePos: 0, baseCur: null, 17 | overlayPos: 0, overlayCur: null 18 | }; 19 | }, 20 | copyState: function(state) { 21 | return { 22 | base: CodeMirror.copyState(base, state.base), 23 | overlay: CodeMirror.copyState(overlay, state.overlay), 24 | basePos: state.basePos, baseCur: null, 25 | overlayPos: state.overlayPos, overlayCur: null 26 | }; 27 | }, 28 | 29 | token: function(stream, state) { 30 | if (stream.start == state.basePos) { 31 | state.baseCur = base.token(stream, state.base); 32 | state.basePos = stream.pos; 33 | } 34 | if (stream.start == state.overlayPos) { 35 | stream.pos = stream.start; 36 | state.overlayCur = overlay.token(stream, state.overlay); 37 | state.overlayPos = stream.pos; 38 | } 39 | stream.pos = Math.min(state.basePos, state.overlayPos); 40 | if (stream.eol()) state.basePos = state.overlayPos = 0; 41 | 42 | if (state.overlayCur == null) return state.baseCur; 43 | if (state.baseCur != null && combine) return state.baseCur + " " + state.overlayCur; 44 | else return state.overlayCur; 45 | }, 46 | 47 | indent: base.indent && function(state, textAfter) { 48 | return base.indent(state.base, textAfter); 49 | }, 50 | electricChars: base.electricChars, 51 | 52 | innerMode: function(state) { return {state: state.base, mode: base}; }, 53 | 54 | blankLine: function(state) { 55 | if (base.blankLine) base.blankLine(state.base); 56 | if (overlay.blankLine) overlay.blankLine(state.overlay); 57 | } 58 | }; 59 | }; 60 | -------------------------------------------------------------------------------- /static/notebook/js/layoutmanager.js: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // Copyright (C) 2008-2011 The IPython Development Team 3 | // 4 | // Distributed under the terms of the BSD License. The full license is in 5 | // the file COPYING, distributed as part of this software. 6 | //---------------------------------------------------------------------------- 7 | 8 | //============================================================================ 9 | // Layout 10 | //============================================================================ 11 | 12 | var IPython = (function (IPython) { 13 | 14 | var LayoutManager = function () { 15 | this.bind_events(); 16 | }; 17 | 18 | 19 | LayoutManager.prototype.bind_events = function () { 20 | $(window).resize($.proxy(this.do_resize,this)); 21 | }; 22 | 23 | LayoutManager.prototype.app_height = function() { 24 | var win = $(window); 25 | var w = win.width(); 26 | var h = win.height(); 27 | var header_height; 28 | if ($('div#header').css('display') === 'none') { 29 | header_height = 0; 30 | } else { 31 | header_height = $('div#header').outerHeight(true); 32 | } 33 | var menubar_height = $('div#menubar').outerHeight(true); 34 | var toolbar_height; 35 | if ($('div#maintoolbar').css('display') === 'none') { 36 | toolbar_height = 0; 37 | } else { 38 | toolbar_height = $('div#maintoolbar').outerHeight(true); 39 | } 40 | return h-header_height-menubar_height-toolbar_height; // content height 41 | } 42 | 43 | LayoutManager.prototype.do_resize = function () { 44 | var app_height = this.app_height() // content height 45 | 46 | $('#ipython-main-app').height(app_height); // content+padding+border height 47 | 48 | var pager_height = IPython.pager.percentage_height*app_height; 49 | var pager_splitter_height = $('div#pager_splitter').outerHeight(true); 50 | $('div#pager').outerHeight(pager_height); 51 | if (IPython.pager.expanded) { 52 | $('div#notebook').outerHeight(app_height-pager_height-pager_splitter_height); 53 | } else { 54 | $('div#notebook').outerHeight(app_height-pager_splitter_height); 55 | } 56 | }; 57 | 58 | IPython.LayoutManager = LayoutManager; 59 | 60 | return IPython; 61 | 62 | }(IPython)); 63 | -------------------------------------------------------------------------------- /static/notebook/js/celltoolbarpresets/slideshow.js: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // Copyright (C) 2012 The IPython Development Team 3 | // 4 | // Distributed under the terms of the BSD License. The full license is in 5 | // the file COPYING, distributed as part of this software. 6 | //---------------------------------------------------------------------------- 7 | 8 | //============================================================================ 9 | //CellToolbar Example 10 | //============================================================================ 11 | 12 | /** 13 | * $.getScript('/static/js/celltoolbarpresets/slideshow.js'); 14 | * ``` 15 | * or more generally 16 | * ``` 17 | * $.getScript('url to this file'); 18 | * ``` 19 | */ 20 | // IIFE without asignement, we don't modifiy the IPython namespace 21 | (function (IPython) { 22 | "use strict"; 23 | 24 | var CellToolbar = IPython.CellToolbar; 25 | var slideshow_preset = []; 26 | 27 | var select_type = CellToolbar.utils.select_ui_generator([ 28 | ["-" ,undefined ], 29 | ["Slide" ,"slide" ], 30 | ["Sub-Slide" ,"subslide" ], 31 | ["Fragment" ,"fragment" ], 32 | ["Skip" ,"skip" ], 33 | ["Notes" ,"notes" ], 34 | ], 35 | // setter 36 | function(cell, value){ 37 | // we check that the slideshow namespace exist and create it if needed 38 | if (cell.metadata.slideshow == undefined){cell.metadata.slideshow = {}} 39 | // set the value 40 | cell.metadata.slideshow.slide_type = value 41 | }, 42 | //geter 43 | function(cell){ var ns = cell.metadata.slideshow; 44 | // if the slideshow namespace does not exist return `undefined` 45 | // (will be interpreted as `false` by checkbox) otherwise 46 | // return the value 47 | return (ns == undefined)? undefined: ns.slide_type 48 | }, 49 | "Slide Type"); 50 | 51 | CellToolbar.register_callback('slideshow.select',select_type); 52 | 53 | slideshow_preset.push('slideshow.select'); 54 | 55 | CellToolbar.register_preset('Slideshow',slideshow_preset); 56 | console.log('Slideshow extension for metadata editing loaded.'); 57 | 58 | }(IPython)); 59 | -------------------------------------------------------------------------------- /static/notebook/js/config.js: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // Copyright (C) 2012 The IPython Development Team 3 | // 4 | // Distributed under the terms of the BSD License. The full license is in 5 | // the file COPYING, distributed as part of this software. 6 | //---------------------------------------------------------------------------- 7 | 8 | //============================================================================ 9 | // Notebook 10 | //============================================================================ 11 | 12 | /** 13 | * @module IPython 14 | * @namespace IPython 15 | **/ 16 | 17 | var IPython = (function (IPython) { 18 | /** 19 | * A place where some stuff can be confugured. 20 | * 21 | * @class config 22 | * @static 23 | * 24 | **/ 25 | var default_config = { 26 | /** 27 | * Dictionary of object to autodetect highlight mode for code cell. 28 | * Item of the dictionnary should take the form : 29 | * 30 | * key : {'reg':[list_of_regexp]} 31 | * 32 | * where `key` will be the code mirror mode name 33 | * and `list_of_regexp` should be a list of regext that should match 34 | * the first line of the cell to trigger this mode. 35 | * 36 | * if `key` is prefixed by the `magic_` prefix the codemirror `mode` 37 | * will be applied only at the end of the first line 38 | * 39 | * @attribute cell_magic_highlight 40 | * @example 41 | * This would trigger javascript mode 42 | * from the second line if first line start with `%%javascript` or `%%jsmagic` 43 | * 44 | * cell_magic_highlight['magic_javascript'] = {'reg':[/^%%javascript/,/^%%jsmagic/]} 45 | * @example 46 | * This would trigger javascript mode 47 | * from the second line if first line start with `var` 48 | * 49 | * cell_magic_highlight['javascript'] = {'reg':[/^var/]} 50 | */ 51 | cell_magic_highlight : { 52 | 'magic_javascript':{'reg':[/^%%javascript/]} 53 | ,'magic_perl' :{'reg':[/^%%perl/]} 54 | ,'magic_ruby' :{'reg':[/^%%ruby/]} 55 | ,'magic_python' :{'reg':[/^%%python3?/]} 56 | ,'magic_shell' :{'reg':[/^%%bash/]} 57 | ,'magic_r' :{'reg':[/^%%R/]} 58 | }, 59 | 60 | /** 61 | * same as `cell_magic_highlight` but for raw cells 62 | * @attribute raw_cell_highlight 63 | */ 64 | raw_cell_highlight : { 65 | 'diff' :{'reg':[/^diff/]} 66 | }, 67 | 68 | tooltip_on_tab : true, 69 | }; 70 | 71 | // use the same method to merge user configuration 72 | IPython.config = {}; 73 | $.extend(IPython.config, default_config); 74 | 75 | return IPython; 76 | 77 | }(IPython)); 78 | 79 | -------------------------------------------------------------------------------- /static/tree/js/main.js: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // Copyright (C) 2008-2011 The IPython Development Team 3 | // 4 | // Distributed under the terms of the BSD License. The full license is in 5 | // the file COPYING, distributed as part of this software. 6 | //---------------------------------------------------------------------------- 7 | 8 | //============================================================================ 9 | // On document ready 10 | //============================================================================ 11 | 12 | 13 | $(document).ready(function () { 14 | 15 | IPython.page = new IPython.Page(); 16 | $('#new_notebook').click(function (e) { 17 | window.open($('body').data('baseProjectUrl')+'new'); 18 | }); 19 | 20 | IPython.notebook_list = new IPython.NotebookList('#notebook_list'); 21 | IPython.cluster_list = new IPython.ClusterList('#cluster_list'); 22 | IPython.login_widget = new IPython.LoginWidget('#login_widget'); 23 | 24 | var interval_id=0; 25 | // auto refresh every xx secondes, no need to be fast, 26 | // update is done at least when page get focus 27 | var time_refresh = 60; // in sec 28 | 29 | var enable_autorefresh = function(){ 30 | //refresh immediately , then start interval 31 | if($('.upload_button').length == 0) 32 | { 33 | IPython.notebook_list.load_list(); 34 | IPython.cluster_list.load_list(); 35 | } 36 | if (!interval_id){ 37 | interval_id = setInterval(function(){ 38 | if($('.upload_button').length == 0) 39 | { 40 | IPython.notebook_list.load_list(); 41 | IPython.cluster_list.load_list(); 42 | } 43 | }, time_refresh*1000); 44 | } 45 | } 46 | 47 | var disable_autorefresh = function(){ 48 | clearInterval(interval_id); 49 | interval_id = 0; 50 | } 51 | 52 | // stop autorefresh when page lose focus 53 | $(window).blur(function() { 54 | disable_autorefresh(); 55 | }) 56 | 57 | //re-enable when page get focus back 58 | $(window).focus(function() { 59 | enable_autorefresh(); 60 | }); 61 | 62 | // finally start it, it will refresh immediately 63 | enable_autorefresh(); 64 | 65 | IPython.page.show(); 66 | 67 | // bound the upload method to the on change of the file select list 68 | $("#alternate_upload").change(function (event){ 69 | IPython.notebook_list.handelFilesUpload(event,'form'); 70 | }); 71 | 72 | // set hash on tab click 73 | $("#tabs").find("a").click(function() { 74 | window.location.hash = $(this).attr("href"); 75 | }) 76 | 77 | // load tab if url hash 78 | if (window.location.hash) { 79 | $("#tabs").find("a[href=" + window.location.hash + "]").click(); 80 | } 81 | 82 | 83 | }); 84 | 85 | -------------------------------------------------------------------------------- /static/notebook/js/notificationwidget.js: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // Copyright (C) 2008-2011 The IPython Development Team 3 | // 4 | // Distributed under the terms of the BSD License. The full license is in 5 | // the file COPYING, distributed as part of this software. 6 | //---------------------------------------------------------------------------- 7 | 8 | //============================================================================ 9 | // Notification widget 10 | //============================================================================ 11 | 12 | var IPython = (function (IPython) { 13 | "use strict"; 14 | var utils = IPython.utils; 15 | 16 | 17 | var NotificationWidget = function (selector) { 18 | this.selector = selector; 19 | this.timeout = null; 20 | this.busy = false; 21 | if (this.selector !== undefined) { 22 | this.element = $(selector); 23 | this.style(); 24 | } 25 | this.element.button(); 26 | this.element.hide(); 27 | var that = this; 28 | 29 | }; 30 | 31 | 32 | NotificationWidget.prototype.style = function () { 33 | this.element.addClass('notification_widget pull-right'); 34 | this.element.addClass('border-box-sizing'); 35 | }; 36 | 37 | // msg : message to display 38 | // timeout : time in ms before diseapearing 39 | // 40 | // if timeout <= 0 41 | // click_callback : function called if user click on notification 42 | // could return false to prevent the notification to be dismissed 43 | NotificationWidget.prototype.set_message = function (msg, timeout, click_callback) { 44 | var callback = click_callback || function() {return false;}; 45 | var that = this; 46 | this.element.html(msg); 47 | this.element.fadeIn(100); 48 | if (this.timeout !== null) { 49 | clearTimeout(this.timeout); 50 | this.timeout = null; 51 | } 52 | if (timeout !== undefined && timeout >=0) { 53 | this.timeout = setTimeout(function () { 54 | that.element.fadeOut(100, function () {that.element.html('');}); 55 | that.timeout = null; 56 | }, timeout); 57 | } else { 58 | this.element.click(function() { 59 | if( callback() != false ) { 60 | that.element.fadeOut(100, function () {that.element.html('');}); 61 | that.element.unbind('click'); 62 | } 63 | if (that.timeout !== undefined) { 64 | that.timeout = undefined; 65 | clearTimeout(that.timeout); 66 | } 67 | }); 68 | } 69 | }; 70 | 71 | 72 | NotificationWidget.prototype.get_message = function () { 73 | return this.element.html(); 74 | }; 75 | 76 | 77 | IPython.NotificationWidget = NotificationWidget; 78 | 79 | return IPython; 80 | 81 | }(IPython)); 82 | 83 | -------------------------------------------------------------------------------- /static/base/js/dialog.js: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // Copyright (C) 2013 The IPython Development Team 3 | // 4 | // Distributed under the terms of the BSD License. The full license is in 5 | // the file COPYING, distributed as part of this software. 6 | //---------------------------------------------------------------------------- 7 | 8 | //============================================================================ 9 | // Utility for modal dialogs with bootstrap 10 | //============================================================================ 11 | 12 | IPython.namespace('IPython.dialog'); 13 | 14 | IPython.dialog = (function (IPython) { 15 | 16 | var modal = function (options) { 17 | var dialog = $("
").addClass("modal").attr("role", "dialog"); 18 | dialog.append( 19 | $("
") 20 | .addClass("modal-header") 21 | .append($("