]> Nishi Git Mirror - gwion.git/commitdiff
:art: Use playground
authorJérémie Astor <fennecdjay@gmail.com>
Sat, 3 Apr 2021 13:20:16 +0000 (15:20 +0200)
committerJérémie Astor <fennecdjay@gmail.com>
Sat, 3 Apr 2021 13:20:45 +0000 (15:20 +0200)
22 files changed:
.github/workflows/build.yml
.gitignore
book.toml
docs/Contributing/ContributingCode.mdr
docs/Overview/First_Steps/InstallingGwion.mdr
docs/Overview/Make.mdr [deleted file]
docs/Overview/declaration.mdr
docs/README.mdr
docs/Reference/ControlFlow/ForLoop.mdr
docs/Reference/ControlFlow/Repeat.mdr
docs/Reference/ControlFlow/whileuntil.mdr
docs/Reference/Functions/Lambdas.mdr
docs/Reference/Functions/README.mdr
docs/Reference/Functions/Variadic.mdr
docs/Reference/Types/Enums.mdr
docs/Reference/Types/Typedefs.mdr
docs/Reference/Types/Unions.mdr
docs/editor_mine.js [new file with mode: 0644]
docs/mode-gwion.js [new file with mode: 0644]
scripts/mdr2mdbook.sh
theme/book.js [new file with mode: 0644]
theme/index.hbs [new file with mode: 0644]

index daf6e983fb98808e60b1005467fefbc3c60a1be4..d7ac6ee838345dd9d94e032d581d7f0b62363724 100644 (file)
@@ -11,10 +11,6 @@ jobs:
     steps:
     - uses: actions/checkout@v1
       name: Checkout
-    - uses: actions/setup-python@v1
-      name: Setup Python
-    - uses: actions/setup-ruby@v1
-      name: Setup Ruby
 
     - name: Dependencies
       run: bash scripts/update.sh
index 04a4376540f32e00af00e0ed96e4799090f8b444..a34cbd92186bcdf188f795dee3f2c2f850ca4e59 100644 (file)
@@ -1,4 +1,4 @@
-src
+#src
 book
 log
 *.gw
index 1ee37e009bde8c5a4194bdc896c18ce8b8d79f25..2d0108bf022575375af9cd2e371b5dd5ff68683b 100644 (file)
--- a/book.toml
+++ b/book.toml
@@ -19,3 +19,7 @@ use-boolean-and = true
 boost-title = 3
 boost-hierarchy = 2
 boost-paragraph = 1
+
+[output.html.playground]
+line-numbers= false
+editable = true
index 7a775146e804c2d68ac330b11c11986bb635dc5c..ba63ebc5cc858a00f49536269439e9ba48bd4d09 100644 (file)
@@ -18,20 +18,17 @@ You can do this through the github site, or command-line tools like `gh` or `hub
 Clone the url of your fork
 
 ``` sh
-git clone https://github.com/<your username>/gwion
+git clone --recursive https://github.com/<your username>/Gwion
 ```
 
 ### Set up the project
-``` sh
-git submodule update --init util ast
-```
 
 ### Edit some files
 
 Edit some files with your favorite text editor
 
 ``` sh
-cd gwion
+cd Gwion
 vim src/path/to/file
 ```
 
index 4107a1785c48c812f87fbe3825ab4f012f2ef5b2..072223cf042a3a274a2c2516a52edbdbd099bad3 100644 (file)
@@ -2,24 +2,17 @@
 
 ## Get the sources
 
-The source is accessible on [github](https:#!github.com).
+The source is accessible on [github](https://github.com).
 
 Provided you have git installed, you can get it with:
 
 ``` sh
-git clone https://github.com/Gwion/gwion
+git clone --recursive https://github.com/Gwion/Gwion
 ```
 
 then change to the source directory
 ``` sh
-cd gwion
-```
-
-### Don't forget submodules
-
-You'll need the sources for all base module
-``` sh
-git submodule update --init util ast
+cd Gwion
 ```
 
 > At this point, you may want to configure the build.
diff --git a/docs/Overview/Make.mdr b/docs/Overview/Make.mdr
deleted file mode 100644 (file)
index 45a5452..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# Makefile
-
-## Basic operations
-
-## translations
-
-## Docs
index 04b83560dcf024176150f79b106d4c35cd7f7d36..5bba1a981f7d95ae390d3b174416433223843de7 100644 (file)
@@ -3,31 +3,28 @@
 ## Basics
 
 Declaring a primitive or an object is quite straight forward:
-@``` decl0.gw
+```gwion,editable
 var int i;
 var Object o;
 <<< i, " ", o >>>;
-@```
-@hide make -s decl0.test
+```
 
 ## Declaring a reference
 
-@``` decl1.gw
+```gwion,editable
 late Object object_ref;
 <<< "Reference points to no object yet: ", object_ref >>>;
 new Object => object_ref;
 <<< "But now it does: ", object_ref >>>;
-@```
-@hide make -s decl1.test
+```
 
 ## Arrays
 
 ### array as refs
 
-@``` decl2.gw
+```gwion,editable
 var int array_ref[];
 <<< array_ref >>>;
 new int[2] => array_ref;
 <<< array_ref >>>;
-@```
-@hide make -s decl2.test
+```
index bdd9742b94c1f3d7db1814748a8dc3a606b56209..d640639e32a55545a6c94bccbd4997865af10851 100644 (file)
@@ -1,6 +1,6 @@
 # Welcome to Gwion
 
-:gwion: is a strongly timed programming language for making music.
+gwion is a strongly timed programming language for making music.
 
 It is strongly influenced by [chuck](http://chuck.stanford.edu/), but adds a bunch of high-level features:
 templating, first-class functions and more.
@@ -13,12 +13,11 @@ We are currently looking for contributions, you can learn how to make some [here
 
 ## And now for the hello world
 
-Here is the piece of code you're waiting for :tada::
+Here is the piece of code you're waiting for:
 
-@```helloworld.gw
+```gwion,editable
 <<< "Hello, World!" >>>;
-@```  
-@hide make -s CONTAINS="Hello, World!" helloworld.test
+```
 
 ## (Bag of) Features
 
index bb7311b5ec9d51ecf3659f4332548c0b784ed2d3..69a44eaf8fa1006891f567ff3efde4481be45ed3 100644 (file)
@@ -2,25 +2,23 @@
 **For** loops in Gwion is pretty similar to classic **C** syntax
 
 ## basic loops
-@``` forloop0.gw
+```gwion,editable
 for(var int i; i < 3; ++i)
    <<< i >>>;
-@```  
-@hide make -s forloop0.test
+```  
 
 It also works with a block of code.
 
-@``` forloop2.gw
+```gwion,editable
 for(var int i; i < 3; ++i) {
    i/2 => var float f1;
    i/2. => var float f2;
    <<< i, " " , f1, " ", f2 >>>;
 }
-@```  
-@hide make -s forloop2.test
+```  
 
 ## Nested Loops
-@``` forloop3.gw
+```gwion,editable
 var int array[3][4];
 
 for(var int i; i < 3; ++i) {
@@ -28,26 +26,24 @@ for(var int i; i < 3; ++i) {
     <<< array[i][j] >>>;
   }
 }
-@```  
-@hide make -s forloop3.test
+```  
 
 ### Auto Loops
 
 #### Simple auto loop
-@``` forloop4.gw
+```gwion,editable
 var int array[2][3];
 foreach(a: array) {
   <<< a >>>;
   foreach(b: a)
     <<< b >>>;
 }
-@```  
-@hide make -s forloop4.test
+```  
 
 ### Auto Pointer loop
 If you want to change it the value in the array, you need a pointer 
 
-@``` forloop5.gw
+```
 var int array[2][3];
 var int i;
 foreach(a: array) {
@@ -58,5 +54,4 @@ foreach(a: array) {
   foreach(b: a)
     <<< b >>>;
 }
-@```  
-@hide make -s forloop5.test
+```  
index a15625a45ace2c852a3291a0f6192f904b1924f9..216596239ac975077d06c0cc57fcb8dc6cc657d5 100644 (file)
@@ -4,21 +4,19 @@ The easiest way to do an action repeatidly in Gwion is, ... the **repeat** keywo
 
 ## Basic example
 
-@``` repeat.gw
+```gwion,editable
 repeat(3)
    <<< "Hello, world!" >>>;
-@```  
-@hide make -s CONTAINS="Hello" repeat.test
+```  
 
 
 ## Block example
 
 of course this also works with a block code.
 
-@``` repeat2.gw
+```gwion,editable
 repeat(3) {
    maybe ? "You" : "Me" => var string s;
    <<< "Hello, ", s, "!" >>>;
 }
-@```  
-@hide make -s CONTAINS="Hello" repeat2.test
+```  
index e352cc72484e54156d5d16ecf186e941a9ff7ad8..480d69f0b84d0f432b8548722d4359ab4a946276 100644 (file)
@@ -1,23 +1,21 @@
 # While Loops
 
-@``` while0.gw
+```gwion,editable
 while(true) {
   if(maybe)
     break;
   <<< "running..." >>>;
 }
-@```  
-@hide make -s while0.test
+```  
 
 well this may output nothing...
 lets try
 
-@``` while1.gw
+```gwion,editable
 <<< maybe >>>;
 do{
   if(maybe)
     break;
   <<< "running..." >>>;
 } while(true);
-@```  
-@hide make -s while1.test
+```  
index 8c234bacc5965893aa6e47487274c57cd5be717e..86ba42105d4e3958f90aca8c85eb1f45c3221c16 100644 (file)
@@ -10,28 +10,25 @@ The syntax to create them is simple:
 ```
 You can even use it to
 ### Call a function just once
-@``` lambda_call0.gw
+```gwion,editable
 \ i { <<< "passed '", i, "'" >>>; }(3);
-@```  
-@hide make -s CONTAINS="passed '3'" lambda_call0.test
+```  
 
 
 ## Use case
 
 ### Passing to a function pointer
-@``` lambda_fptr0.gw
+```gwion,editable
 funcdef void fptr_t(int);
 \ i { <<< "passed '", i, "'" >>>; } => var fptr_t fptr;
 fptr(4);
-@```  
-@hide make -s CONTAINS="passed '4'" lambda_fptr0.test
+```  
 
 ### As Argument to Functions
-@``` lambda_args0.gw
+```gwion,editable
 funcdef void fptr_t(int);
 fun void test(fptr_t fptr) {
    fptr(5);
 }
 test(\ i { <<< "passed '", i, "'" >>>; });
-@```  
-@hide make -s CONTAINS="passed '5'" lambda_args0.test
+```  
index 8fd1bb98f7b8704e7c0bf54cf46c291f4ff7d110..80fb62b92532ecb8a41640090a2556d5268d6397 100644 (file)
@@ -2,7 +2,7 @@
 
 ## a simple (commented example)
 
-@``` function0.gw
+```gwion,editable
 #! declare function 'test_function'
 #! with return type int
 #! taking an int as argument
@@ -15,5 +15,4 @@ fun int test_function(int arg) {
 <<< test_function(0) >>>;
 #! or use alternate syntax
 <<< 1 => test_function >>>;
-@```
-@hide make -s function0.test
+```
index b53da62fa24c24265410e4a88a7ffcb0dfb77438..44f95e36add4dcec50ff1a37e72f00de91b31486 100644 (file)
@@ -5,7 +5,7 @@
 Well, a function that takes a fixed number of arguments, and additionnal ones.
 
 ## a simple example
-@``` variadic.gw
+```gwion,editable
 fun void variadic_test(int i, ...) {
   <<<  "first argument is ", i  >>>;
   varloop vararg {
@@ -15,5 +15,4 @@ fun void variadic_test(int i, ...) {
 variadic_test(1);
 variadic_test(1, 2);
 variadic_test(1, 2, 3);
-@```
-@hide make -s variadic.test
+```
index ed1e3ab7e08af609cf43c7c6a259f21b261b1edd..35802b5847ff8dfa89fc1a1a50c3cee046212093 100644 (file)
@@ -9,13 +9,12 @@ you can read about those
 
 You use an enum like this
 
-@``` enum0.gw
+```gwion,editable
 enum Optionnal_name {
   zero, one, two
 };
 <<< zero, one, two >>>;
-@```
-@hide make -s enum0.test
+```
 
 ## Storage and access Specifiers
 
index 332cde614f958e9df4c0494bdd2b3fcf4bda86fd..3a26421d277a85728c07c3418cc345f5d4f37ab5 100644 (file)
@@ -2,27 +2,27 @@
 
 Create an alias for a previously defined type.
 
-@``` typedef_simple.gw
+```gwion,editable
 typedef int MyInt;
 var MyInt i;
 <<< i >>>;
 <<< i $ int >>>;
-@```
+```
 
 Aliases can also point to an array type
 
-@``` typedef_array.gw
+```gwion,editable
 typedef float[3] Point;
 var Point p;
 foreach(a : p)
   <<< a >>>;
-@```
+```
 
 
 Aliases can be used to refer to a type family
 
-@``` typedef_tmpl.gw
+```gwion,editable
 typedef Ptr:[int] IntPtr;
 var IntPtr int_ptr;
 <<< int_ptr >>>;
-@```
+```
index 128c62576cafa06205f6c555cc79c9431555f569..9c39ad559cb81dd5e7c0e703e6180be27cb96c9d 100644 (file)
@@ -3,11 +3,11 @@
 Union store their component in the same memory space.
 For more infomations, see [here](https://en.wikipedia.org/wiki/Union_type).
 
-@``` base_union
+```gwion,editable
 union U {
   int a;
   float f;
   Object o;
 };
-@```
+```
 
diff --git a/docs/editor_mine.js b/docs/editor_mine.js
new file mode 100644 (file)
index 0000000..b9b39a7
--- /dev/null
@@ -0,0 +1,26 @@
+"use strict";
+window.editors = [];
+(function(editors) {
+    if (typeof(ace) === 'undefined' || !ace) {
+        return;
+    }
+    Array.from(document.querySelectorAll('.editable')).forEach(function(editable) {
+        let editor = ace.edit(editable);
+            editor.setOptions({
+            theme: 'ace/theme/tomorrow_night',
+            mode: 'ace/mode/gwion'
+        });
+
+        editable.addEventListener('mouseenter', e => {
+            editor.setOptions({
+                highlightActiveLine: true
+            });
+        });
+        editable.addEventListener('mouseleave', e => {
+            editor.setOptions({
+                highlightActiveLine: false
+            });
+        });
+
+    });
+})(window.editors);
diff --git a/docs/mode-gwion.js b/docs/mode-gwion.js
new file mode 100644 (file)
index 0000000..7fb88ce
--- /dev/null
@@ -0,0 +1,250 @@
+ace.define("ace/mode/gwion_highlight_rules", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text_highlight_rules"], function(e, t, n) {
+    "use strict";
+    var interp = 0;
+    var r = e("../lib/oop")
+      , i = e("./text_highlight_rules").TextHighlightRules
+      , s = /\\(?:[nrt0'"\\]|x[\da-fA-F]{2}|u\{[\da-fA-F]{6}\})/.source
+      , o = function() {
+        this.$rules = {
+            start: [{
+                token: "variable.other.source.gwion",
+                regex: "'[a-zA-Z_][a-zA-Z0-9_]*"
+            }, {
+                token: "string.quoted.single.source.gwion",
+                regex: "'(?:[^'\\\\]|" + s + ")'"
+            }, {
+                token: "identifier",
+                regex: /r#[a-zA-Z_][a-zA-Z0-9_]*\b/
+            }, {
+                stateName: "bracketedComment",
+                onMatch: function(e, t, n) {
+                    return n.unshift(this.next, e.length - 1, t),
+                    "string.quoted.raw.source.gwion"
+                },
+                regex: /r#*"/,
+                next: [{
+                    onMatch: function(e, t, n) {
+                        var r = "string.quoted.raw.source.gwion";
+                        return e.length >= n[1] ? (e.length > n[1] && (r = "invalid"),
+                        n.shift(),
+                        n.shift(),
+                        this.next = n.shift()) : this.next = "",
+                        r
+                    },
+                    regex: /"#*/,
+                    next: "start"
+                }, {
+                    defaultToken: "string.quoted.raw.source.gwion"
+                }]
+            }, {
+                token: "string.quoted.double.source.gwion",
+                regex: '"',
+                push: [{
+                    token: "string.quoted.double.source.gwion",
+                    regex: '"',
+                    next: "pop"
+                }, {
+                    token: "constant.character.escape.source.gwion",
+                    regex: s
+                }, {
+                    defaultToken: "string.quoted.double.source.gwion"
+                }]
+            }, {
+                token: ["keyword.source.gwion", "text", "entity.name.function.source.gwion"],
+                regex: "\\b(fn)(\\s+)((?:r#)?[a-zA-Z_][a-zA-Z0-9_]*)"
+            }, {
+                token: "support.constant",
+                regex: "\\b[a-zA-Z_][\\w\\d]*::"
+            }, {
+                token: "keyword.source.gwion",
+                regex: "\\b(?:abstract|defer|repeat|foreach|break|continue|const|var|late|do|else|enum|for|final|if|extends|match|case|private|protect|global|return|self|static|public|class|struct|fun|operator|funcdef|trait|union|where|when|while|new)\\b"
+            }, {
+                token: "storage.type.source.gwion",
+                regex: "\\b(?:Self|int|float|string|Event|Object|bool|Option|Ref|Array)\\b"
+            }, {
+                token: "variable.language.source.gwion",
+                regex: "\\b(?:self|this|me|adc|dac)\\b"
+            }, {
+                token: "comment.line.doc.source.gwion",
+                regex: "#!!.*$"
+            }, {
+                token: "comment.block.source.gwion",
+                regex: "#!.*!#",
+            }, {
+                token: "comment.line.double-dash.source.gwion",
+                regex: "#!.*$"
+            }, {
+                token: "keyword.operator",
+                regex: /\$|[-=]>|[-+%^=!&|<>~:]=?|[*/](?![*/>])=?/
+            }, {
+                token: "punctuation.operator",
+                regex: /[?:,;.]/
+            }, {
+                token: "paren.lparen",
+                regex: /[\[({]/
+            }, {
+                token: "paren.rparen",
+                regex: /[\])}]/
+            }, {
+                token: "constant.language.source.gwion",
+                regex: "\\b(?:true|false|maybe|None)\\b"
+            }, {
+                token: "support.constant.source.gwion",
+                regex: "\\b(?:pi|EXIT_FAILURE|EXIT_SUCCESS|RAND_MAX|EOF|SEEK_SET|SEEK_CUR|SEEK_END|_IOFBF|_IONBF|_IOLBF|BUFSIZ|FOPEN_MAX|FILENAME_MAX|L_tmpnam|TMP_MAX|O_RDONLY|O_WRONLY|O_RDWR|O_APPEND|O_CREAT|O_EXCL|O_TRUNC|S_IFIFO|S_IFCHR|S_IFBLK|S_IFDIR|S_IFREG|S_IFMT|S_IEXEC|S_IWRITE|S_IREAD|S_IRWXU|S_IXUSR|S_IWUSR|S_IRUSR|F_OK|R_OK|W_OK|X_OK|STDIN_FILENO|STDOUT_FILENO|STDERR_FILENO)\\b"
+            }, {
+                token: "meta.preprocessor.source.gwion",
+                regex : "#\\s*(?:include|require|pragma|__line__|__file__|__func__|ifdef|undef|define|undef)\\b"
+            }, {
+                token: "constant.numeric.source.gwion",
+                regex: /\b(?:0x[a-fA-F0-9_]+|0o[0-7_]+|0b[01_]+|[0-9][0-9_]*(?!\.))(?:[iu](?:size|8|16|32|64|128))?\b/
+            }, {
+                token: "constant.numeric.source.gwion",
+                regex: /\b(?:[0-9][0-9_]*)(?:\.[0-9][0-9_]*)?(?:[Ee][+-][0-9][0-9_]*)?(?:f32|f64)?\b/
+            }]
+        },
+        this.normalizeRules()
+    };
+    o.metaData = {
+        fileTypes: ["rs", "rc"],
+        foldingStartMarker: "^.*\\bfn\\s*(\\w+\\s*)?\\([^\\)]*\\)(\\s*\\{[^\\}]*)?\\s*$",
+        foldingStopMarker: "^\\s*\\}",
+        name: "Rust",
+        scopeName: "source.gwion"
+    },
+    r.inherits(o, i),
+    t.RustHighlightRules = o
+}),
+ace.define("ace/mode/folding/cstyle", ["require", "exports", "module", "ace/lib/oop", "ace/range", "ace/mode/folding/fold_mode"], function(e, t, n) {
+    "use strict";
+    var r = e("../../lib/oop")
+      , i = e("../../range").Range
+      , s = e("./fold_mode").FoldMode
+      , o = t.FoldMode = function(e) {
+        e && (this.foldingStartMarker = new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/, "|" + e.start)),
+        this.foldingStopMarker = new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/, "|" + e.end)))
+    }
+    ;
+    r.inherits(o, s),
+    function() {
+        this.foldingStartMarker = /([\{\[\(])[^\}\]\)]*$|^\s*(\/\*)/,
+        this.foldingStopMarker = /^[^\[\{\(]*([\}\]\)])|^[\s\*]*(\*\/)/,
+        this.singleLineBlockCommentRe = /^\s*(\/\*).*\*\/\s*$/,
+        this.tripleStarBlockCommentRe = /^\s*(\/\*\*\*).*\*\/\s*$/,
+        this.startRegionRe = /^\s*(\/\*|\/\/)#?region\b/,
+        this._getFoldWidgetBase = this.getFoldWidget,
+        this.getFoldWidget = function(e, t, n) {
+            var r = e.getLine(n);
+            if (this.singleLineBlockCommentRe.test(r) && !this.startRegionRe.test(r) && !this.tripleStarBlockCommentRe.test(r))
+                return "";
+            var i = this._getFoldWidgetBase(e, t, n);
+            return !i && this.startRegionRe.test(r) ? "start" : i
+        }
+        ,
+        this.getFoldWidgetRange = function(e, t, n, r) {
+            var i = e.getLine(n);
+            if (this.startRegionRe.test(i))
+                return this.getCommentRegionBlock(e, i, n);
+            var s = i.match(this.foldingStartMarker);
+            if (s) {
+                var o = s.index;
+                if (s[1])
+                    return this.openingBracketBlock(e, s[1], n, o);
+                var u = e.getCommentFoldRange(n, o + s[0].length, 1);
+                return u && !u.isMultiLine() && (r ? u = this.getSectionRange(e, n) : t != "all" && (u = null)),
+                u
+            }
+            if (t === "markbegin")
+                return;
+            var s = i.match(this.foldingStopMarker);
+            if (s) {
+                var o = s.index + s[0].length;
+                return s[1] ? this.closingBracketBlock(e, s[1], n, o) : e.getCommentFoldRange(n, o, -1)
+            }
+        }
+        ,
+        this.getSectionRange = function(e, t) {
+            var n = e.getLine(t)
+              , r = n.search(/\S/)
+              , s = t
+              , o = n.length;
+            t += 1;
+            var u = t
+              , a = e.getLength();
+            while (++t < a) {
+                n = e.getLine(t);
+                var f = n.search(/\S/);
+                if (f === -1)
+                    continue;
+                if (r > f)
+                    break;
+                var l = this.getFoldWidgetRange(e, "all", t);
+                if (l) {
+                    if (l.start.row <= s)
+                        break;
+                    if (l.isMultiLine())
+                        t = l.end.row;
+                    else if (r == f)
+                        break
+                }
+                u = t
+            }
+            return new i(s,o,u,e.getLine(u).length)
+        }
+        ,
+        this.getCommentRegionBlock = function(e, t, n) {
+            var r = t.search(/\s*$/)
+              , s = e.getLength()
+              , o = n
+              , u = /^\s*(?:\/\*|\/\/|--)#?(end)?region\b/
+              , a = 1;
+            while (++n < s) {
+                t = e.getLine(n);
+                var f = u.exec(t);
+                if (!f)
+                    continue;
+                f[1] ? a-- : a++;
+                if (!a)
+                    break
+            }
+            var l = n;
+            if (l > o)
+                return new i(o,r,l,t.length)
+        }
+    }
+    .call(o.prototype)
+}),
+ace.define("ace/mode/gwion", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text", "ace/mode/gwion_highlight_rules", "ace/mode/folding/cstyle"], function(e, t, n) {
+    "use strict";
+    var r = e("../lib/oop")
+      , i = e("./text").Mode
+      , s = e("./gwion_highlight_rules").RustHighlightRules
+      , o = e("./folding/cstyle").FoldMode
+      , u = function() {
+        this.HighlightRules = s,
+        this.foldingRules = new o,
+        this.$behaviour = this.$defaultBehaviour
+    };
+    r.inherits(u, i),
+    function() {
+        this.lineCommentStart = "//",
+        this.blockComment = {
+            start: "/*",
+            end: "*/",
+            nestable: !0
+        },
+        this.$quotes = {
+            '"': '"'
+        },
+        this.$id = "ace/mode/gwion"
+    }
+    .call(u.prototype),
+    t.Mode = u
+});
+(function() {
+    ace.require(["ace/mode/gwion"], function(m) {
+        if (typeof module == "object" && typeof exports == "object" && module) {
+            module.exports = m;
+        }
+    });
+}
+)();
index 4891e41a02f7c106e2f2767e246fe68c9ecb4d67..edfd542ad70f2c6adf4d493cf24926c40181d2a5 100644 (file)
@@ -27,6 +27,7 @@ doc2src() {
   target=$(sed 's/docs/src/' <<< $mdfile)
   ensure_dir $target
   mk_target $mdfile > $target
+#  mv $mdfile $target
   rm $mdfile
 }
 
@@ -44,3 +45,4 @@ then bash scripts/summary.sh > src/SUMMARY.md
 fi
 else runall
 fi
+cp docs/*.js src
diff --git a/theme/book.js b/theme/book.js
new file mode 100644 (file)
index 0000000..43a4ded
--- /dev/null
@@ -0,0 +1,574 @@
+"use strict";
+
+// Fix back button cache problem
+window.onunload = function () { };
+
+// Global variable, shared between modules
+function playground_text(playground) {
+
+    let code_block = playground.querySelector("code");
+
+    if (window.ace && code_block.classList.contains("editable")) {
+        let editor = window.ace.edit(code_block);
+        return editor.getValue();
+    } else {
+        return code_block.textContent;
+    }
+}
+
+(function codeSnippets() {
+    Array.from(document.querySelectorAll(".language-gwion")).forEach((element) => {
+        let parent = element.parentNode;
+        let wrapper = document.createElement('pre');
+        wrapper.className = 'playground';
+        // set the wrapper as child (instead of the element)
+        parent.replaceChild(wrapper, element);
+        // set element as child of wrapper
+        wrapper.appendChild(element);
+    });
+
+
+    function fetch_with_timeout(url, options, timeout = 60000) {
+        return Promise.race([
+            fetch(url, options),
+            new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
+        ]);
+    }
+
+    var playgrounds = Array.from(document.querySelectorAll(".playground"));
+
+    function run_gwion_code(code_block) {
+        var result_block = code_block.querySelector(".result");
+        if (!result_block) {
+            result_block = document.createElement('code');
+            result_block.className = 'result hljs f9 b9';
+
+            result_block.innerHTML = `<code>${result_block.innerHTML}</code>`
+            code_block.append(result_block);
+        }
+
+        let text = playground_text(code_block);
+
+        result_block.innerText = "Running...";
+
+        fetch_with_timeout("https://TheGwionPlayground.fennecdjay.repl.co", {
+            headers: {
+                'Content-Type': "text/plain",
+            },
+            method: 'POST',
+            mode: 'cors',
+            body: text
+        })
+        .then(response => response.json())
+        .then(response => result_block.innerHTML = response)
+        .catch(error => result_block.innerText = "Playground Communication: " + error.message);
+    }
+
+    // Syntax highlighting Configuration
+    hljs.configure({
+        tabReplace: '    ', // 4 spaces
+        languages: [],      // Languages used for auto-detection
+    });
+
+    let code_nodes = Array
+        .from(document.querySelectorAll('code'))
+        // Don't highlight `inline code` blocks in headers.
+        .filter(function (node) {return !node.parentElement.classList.contains("header"); });
+
+    if (window.ace) {
+        // language-gwion class needs to be removed for editable
+        // blocks or highlightjs will capture events
+        Array
+            .from(document.querySelectorAll('code.editable'))
+            .forEach(function (block) {
+               block.classList.remove('language-gwion');
+                let editor = window.ace.edit(block);
+                editor.commands.addCommand({
+                    name: "run",
+                    bindKey: {
+                        win: "Ctrl-Enter",
+                        mac: "Ctrl-Enter"
+                    },
+                    exec: _editor => run_gwion_code(block.parentNode)
+                });
+            });
+
+        Array
+            .from(document.querySelectorAll('code:not(.editable)'))
+            .forEach(function (block) { hljs.highlightBlock(block); });
+    } else {
+        code_nodes.forEach(function (block) { hljs.highlightBlock(block); });
+    }
+
+    // Adding the hljs class gives code blocks the color css
+    // even if highlighting doesn't apply
+    code_nodes.forEach(function (block) { block.classList.add('hljs'); });
+
+    if (window.playground_copyable) {
+        Array.from(document.querySelectorAll('pre code')).forEach(function (block) {
+            var pre_block = block.parentNode;
+            if (!pre_block.classList.contains('playground')) {
+                var buttons = pre_block.querySelector(".buttons");
+                if (!buttons) {
+                    buttons = document.createElement('div');
+                    buttons.className = 'buttons';
+                    pre_block.insertBefore(buttons, pre_block.firstChild);
+                }
+
+                var clipButton = document.createElement('button');
+                clipButton.className = 'fa fa-copy clip-button';
+                clipButton.title = 'Copy to clipboard';
+                clipButton.setAttribute('aria-label', clipButton.title);
+                clipButton.innerHTML = '<i class=\"tooltiptext\"></i>';
+
+                buttons.insertBefore(clipButton, buttons.firstChild);
+            }
+        });
+    }
+
+    // Process playground code blocks
+    Array.from(document.querySelectorAll(".playground")).forEach(function (pre_block) {
+        // Add play button
+        var buttons = pre_block.querySelector(".buttons");
+        if (!buttons) {
+            buttons = document.createElement('div');
+            buttons.className = 'buttons';
+            pre_block.insertBefore(buttons, pre_block.firstChild);
+        }
+
+        var runCodeButton = document.createElement('button');
+        runCodeButton.className = 'fa fa-play play-button';
+        runCodeButton.hidden = true;
+        runCodeButton.title = 'Run this code';
+        runCodeButton.setAttribute('aria-label', runCodeButton.title);
+
+        buttons.insertBefore(runCodeButton, buttons.firstChild);
+        runCodeButton.addEventListener('click', function (e) {
+            run_gwion_code(pre_block);
+        });
+
+        if (window.playground_copyable) {
+            var copyCodeClipboardButton = document.createElement('button');
+            copyCodeClipboardButton.className = 'fa fa-copy clip-button';
+            copyCodeClipboardButton.innerHTML = '<i class="tooltiptext"></i>';
+            copyCodeClipboardButton.title = 'Copy to clipboard';
+            copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title);
+
+            buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild);
+        }
+
+        let code_block = pre_block.querySelector("code");
+
+
+        if (window.ace && code_block.classList.contains("editable")) {
+            var undoChangesButton = document.createElement('button');
+            undoChangesButton.className = 'fa fa-history reset-button';
+            undoChangesButton.title = 'Undo changes';
+            undoChangesButton.setAttribute('aria-label', undoChangesButton.title);
+
+            buttons.insertBefore(undoChangesButton, buttons.firstChild);
+
+            undoChangesButton.addEventListener('click', function () {
+                let editor = window.ace.edit(code_block);
+                editor.setValue(editor.originalCode);
+                editor.clearSelection();
+            });
+        }
+
+        const play_button = pre_block.querySelector(".play-button");
+
+        // skip if code is `no_run`
+        if (pre_block.querySelector('code').classList.contains("no_run")) {
+            play_button.classList.add("hidden");
+            return;
+        }
+    });
+})();
+
+(function themes() {
+    var html = document.querySelector('html');
+    var themeToggleButton = document.getElementById('theme-toggle');
+    var themePopup = document.getElementById('theme-list');
+    var themeColorMetaTag = document.querySelector('meta[name="theme-color"]');
+    var stylesheets = {
+        ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"),
+        tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"),
+        highlight: document.querySelector("[href$='highlight.css']"),
+    };
+
+    function showThemes() {
+        themePopup.style.display = 'block';
+        themeToggleButton.setAttribute('aria-expanded', true);
+        themePopup.querySelector("button#" + get_theme()).focus();
+    }
+
+    function hideThemes() {
+        themePopup.style.display = 'none';
+        themeToggleButton.setAttribute('aria-expanded', false);
+        themeToggleButton.focus();
+    }
+
+    function get_theme() {
+        var theme;
+        try { theme = localStorage.getItem('mdbook-theme'); } catch (e) { }
+        if (theme === null || theme === undefined) {
+            return default_theme;
+        } else {
+            return theme;
+        }
+    }
+
+    function set_theme(theme, store = true) {
+        let ace_theme;
+
+        if (theme == 'coal' || theme == 'navy') {
+            stylesheets.ayuHighlight.disabled = true;
+            stylesheets.tomorrowNight.disabled = false;
+            stylesheets.highlight.disabled = true;
+
+            ace_theme = "ace/theme/tomorrow_night";
+        } else if (theme == 'ayu') {
+            stylesheets.ayuHighlight.disabled = false;
+            stylesheets.tomorrowNight.disabled = true;
+            stylesheets.highlight.disabled = true;
+            ace_theme = "ace/theme/tomorrow_night";
+        } else {
+            stylesheets.ayuHighlight.disabled = true;
+            stylesheets.tomorrowNight.disabled = true;
+            stylesheets.highlight.disabled = false;
+            ace_theme = "ace/theme/dawn";
+        }
+
+        setTimeout(function () {
+            themeColorMetaTag.content = getComputedStyle(document.body).backgroundColor;
+        }, 1);
+
+        if (window.ace && window.editors) {
+            window.editors.forEach(function (editor) {
+                editor.setTheme(ace_theme);
+            });
+        }
+
+        var previousTheme = get_theme();
+
+        if (store) {
+            try { localStorage.setItem('mdbook-theme', theme); } catch (e) { }
+        }
+
+        html.classList.remove(previousTheme);
+        html.classList.add(theme);
+    }
+
+    // Set theme
+    var theme = get_theme();
+
+    set_theme(theme, false);
+
+    themeToggleButton.addEventListener('click', function () {
+        if (themePopup.style.display === 'block') {
+            hideThemes();
+        } else {
+            showThemes();
+        }
+    });
+
+    themePopup.addEventListener('click', function (e) {
+        var theme = e.target.id || e.target.parentElement.id;
+        set_theme(theme);
+    });
+
+    themePopup.addEventListener('focusout', function(e) {
+        // e.relatedTarget is null in Safari and Firefox on macOS (see workaround below)
+        if (!!e.relatedTarget && !themeToggleButton.contains(e.relatedTarget) && !themePopup.contains(e.relatedTarget)) {
+            hideThemes();
+        }
+    });
+
+    // Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628
+    document.addEventListener('click', function(e) {
+        if (themePopup.style.display === 'block' && !themeToggleButton.contains(e.target) && !themePopup.contains(e.target)) {
+            hideThemes();
+        }
+    });
+
+    document.addEventListener('keydown', function (e) {
+        if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
+        if (!themePopup.contains(e.target)) { return; }
+
+        switch (e.key) {
+            case 'Escape':
+                e.preventDefault();
+                hideThemes();
+                break;
+            case 'ArrowUp':
+                e.preventDefault();
+                var li = document.activeElement.parentElement;
+                if (li && li.previousElementSibling) {
+                    li.previousElementSibling.querySelector('button').focus();
+                }
+                break;
+            case 'ArrowDown':
+                e.preventDefault();
+                var li = document.activeElement.parentElement;
+                if (li && li.nextElementSibling) {
+                    li.nextElementSibling.querySelector('button').focus();
+                }
+                break;
+            case 'Home':
+                e.preventDefault();
+                themePopup.querySelector('li:first-child button').focus();
+                break;
+            case 'End':
+                e.preventDefault();
+                themePopup.querySelector('li:last-child button').focus();
+                break;
+        }
+    });
+})();
+
+(function sidebar() {
+    var html = document.querySelector("html");
+    var sidebar = document.getElementById("sidebar");
+    var sidebarLinks = document.querySelectorAll('#sidebar a');
+    var sidebarToggleButton = document.getElementById("sidebar-toggle");
+    var sidebarResizeHandle = document.getElementById("sidebar-resize-handle");
+    var firstContact = null;
+
+    function showSidebar() {
+        html.classList.remove('sidebar-hidden')
+        html.classList.add('sidebar-visible');
+        Array.from(sidebarLinks).forEach(function (link) {
+            link.setAttribute('tabIndex', 0);
+        });
+        sidebarToggleButton.setAttribute('aria-expanded', true);
+        sidebar.setAttribute('aria-hidden', false);
+        try { localStorage.setItem('mdbook-sidebar', 'visible'); } catch (e) { }
+    }
+
+
+    var sidebarAnchorToggles = document.querySelectorAll('#sidebar a.toggle');
+
+    function toggleSection(ev) {
+        ev.currentTarget.parentElement.classList.toggle('expanded');
+    }
+
+    Array.from(sidebarAnchorToggles).forEach(function (el) {
+        el.addEventListener('click', toggleSection);
+    });
+
+    function hideSidebar() {
+        html.classList.remove('sidebar-visible')
+        html.classList.add('sidebar-hidden');
+        Array.from(sidebarLinks).forEach(function (link) {
+            link.setAttribute('tabIndex', -1);
+        });
+        sidebarToggleButton.setAttribute('aria-expanded', false);
+        sidebar.setAttribute('aria-hidden', true);
+        try { localStorage.setItem('mdbook-sidebar', 'hidden'); } catch (e) { }
+    }
+
+    // Toggle sidebar
+    sidebarToggleButton.addEventListener('click', function sidebarToggle() {
+        if (html.classList.contains("sidebar-hidden")) {
+            var current_width = parseInt(
+                document.documentElement.style.getPropertyValue('--sidebar-width'), 10);
+            if (current_width < 150) {
+                document.documentElement.style.setProperty('--sidebar-width', '150px');
+            }
+            showSidebar();
+        } else if (html.classList.contains("sidebar-visible")) {
+            hideSidebar();
+        } else {
+            if (getComputedStyle(sidebar)['transform'] === 'none') {
+                hideSidebar();
+            } else {
+                showSidebar();
+            }
+        }
+    });
+
+    sidebarResizeHandle.addEventListener('mousedown', initResize, false);
+
+    function initResize(e) {
+        window.addEventListener('mousemove', resize, false);
+        window.addEventListener('mouseup', stopResize, false);
+        html.classList.add('sidebar-resizing');
+    }
+    function resize(e) {
+        var pos = (e.clientX - sidebar.offsetLeft);
+        if (pos < 20) {
+            hideSidebar();
+        } else {
+            if (html.classList.contains("sidebar-hidden")) {
+                showSidebar();
+            }
+            pos = Math.min(pos, window.innerWidth - 100);
+            document.documentElement.style.setProperty('--sidebar-width', pos + 'px');
+        }
+    }
+    //on mouseup remove windows functions mousemove & mouseup
+    function stopResize(e) {
+        html.classList.remove('sidebar-resizing');
+        window.removeEventListener('mousemove', resize, false);
+        window.removeEventListener('mouseup', stopResize, false);
+    }
+
+    document.addEventListener('touchstart', function (e) {
+        firstContact = {
+            x: e.touches[0].clientX,
+            time: Date.now()
+        };
+    }, { passive: true });
+
+    document.addEventListener('touchmove', function (e) {
+        if (!firstContact)
+            return;
+
+        var curX = e.touches[0].clientX;
+        var xDiff = curX - firstContact.x,
+            tDiff = Date.now() - firstContact.time;
+
+        if (tDiff < 250 && Math.abs(xDiff) >= 150) {
+            if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300))
+                showSidebar();
+            else if (xDiff < 0 && curX < 300)
+                hideSidebar();
+
+            firstContact = null;
+        }
+    }, { passive: true });
+
+    // Scroll sidebar to current active section
+    var activeSection = document.getElementById("sidebar").querySelector(".active");
+    if (activeSection) {
+        // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
+        activeSection.scrollIntoView({ block: 'center' });
+    }
+})();
+
+(function chapterNavigation() {
+    document.addEventListener('keydown', function (e) {
+        if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
+        if (window.search && window.search.hasFocus()) { return; }
+
+        switch (e.key) {
+            case 'ArrowRight':
+                e.preventDefault();
+                var nextButton = document.querySelector('.nav-chapters.next');
+                if (nextButton) {
+                    window.location.href = nextButton.href;
+                }
+                break;
+            case 'ArrowLeft':
+                e.preventDefault();
+                var previousButton = document.querySelector('.nav-chapters.previous');
+                if (previousButton) {
+                    window.location.href = previousButton.href;
+                }
+                break;
+        }
+    });
+})();
+
+(function clipboard() {
+    var clipButtons = document.querySelectorAll('.clip-button');
+
+    function hideTooltip(elem) {
+        elem.firstChild.innerText = "";
+        elem.className = 'fa fa-copy clip-button';
+    }
+
+    function showTooltip(elem, msg) {
+        elem.firstChild.innerText = msg;
+        elem.className = 'fa fa-copy tooltipped';
+    }
+
+    var clipboardSnippets = new ClipboardJS('.clip-button', {
+        text: function (trigger) {
+            hideTooltip(trigger);
+            let playground = trigger.closest("pre");
+            return playground_text(playground);
+        }
+    });
+
+    Array.from(clipButtons).forEach(function (clipButton) {
+        clipButton.addEventListener('mouseout', function (e) {
+            hideTooltip(e.currentTarget);
+        });
+    });
+
+    clipboardSnippets.on('success', function (e) {
+        e.clearSelection();
+        showTooltip(e.trigger, "Copied!");
+    });
+
+    clipboardSnippets.on('error', function (e) {
+        showTooltip(e.trigger, "Clipboard error!");
+    });
+})();
+
+(function scrollToTop () {
+    var menuTitle = document.querySelector('.menu-title');
+
+    menuTitle.addEventListener('click', function () {
+        document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' });
+    });
+})();
+
+(function controllMenu() {
+    var menu = document.getElementById('menu-bar');
+
+    (function controllPosition() {
+        var scrollTop = document.scrollingElement.scrollTop;
+        var prevScrollTop = scrollTop;
+        var minMenuY = -menu.clientHeight - 50;
+        // When the script loads, the page can be at any scroll (e.g. if you reforesh it).
+        menu.style.top = scrollTop + 'px';
+        // Same as parseInt(menu.style.top.slice(0, -2), but faster
+        var topCache = menu.style.top.slice(0, -2);
+        menu.classList.remove('sticky');
+        var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster
+        document.addEventListener('scroll', function () {
+            scrollTop = Math.max(document.scrollingElement.scrollTop, 0);
+            // `null` means that it doesn't need to be updated
+            var nextSticky = null;
+            var nextTop = null;
+            var scrollDown = scrollTop > prevScrollTop;
+            var menuPosAbsoluteY = topCache - scrollTop;
+            if (scrollDown) {
+                nextSticky = false;
+                if (menuPosAbsoluteY > 0) {
+                    nextTop = prevScrollTop;
+                }
+            } else {
+                if (menuPosAbsoluteY > 0) {
+                    nextSticky = true;
+                } else if (menuPosAbsoluteY < minMenuY) {
+                    nextTop = prevScrollTop + minMenuY;
+                }
+            }
+            if (nextSticky === true && stickyCache === false) {
+                menu.classList.add('sticky');
+                stickyCache = true;
+            } else if (nextSticky === false && stickyCache === true) {
+                menu.classList.remove('sticky');
+                stickyCache = false;
+            }
+            if (nextTop !== null) {
+                menu.style.top = nextTop + 'px';
+                topCache = nextTop;
+            }
+            prevScrollTop = scrollTop;
+        }, { passive: true });
+    })();
+    (function controllBorder() {
+        menu.classList.remove('bordered');
+        document.addEventListener('scroll', function () {
+            if (menu.offsetTop === 0) {
+                menu.classList.remove('bordered');
+            } else {
+                menu.classList.add('bordered');
+            }
+        }, { passive: true });
+    })();
+})();
diff --git a/theme/index.hbs b/theme/index.hbs
new file mode 100644 (file)
index 0000000..e5191f7
--- /dev/null
@@ -0,0 +1,307 @@
+<!DOCTYPE HTML>
+<html lang="{{ language }}" class="sidebar-visible no-js {{ default_theme }}">
+    <head>
+        <!-- Book generated using mdBook -->
+        <meta charset="UTF-8">
+        <title>{{ title }}</title>
+        {{#if is_print }}
+        <meta name="robots" content="noindex" />
+        {{/if}}
+        {{#if base_url}}
+        <base href="{{ base_url }}">
+        {{/if}}
+
+
+        <!-- Custom HTML head -->
+        {{> head}}
+
+        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+        <meta name="description" content="{{ description }}">
+        <meta name="viewport" content="width=device-width, initial-scale=1">
+        <meta name="theme-color" content="#ffffff" />
+
+        {{#if favicon_svg}}
+        <link rel="icon" href="{{ path_to_root }}favicon.svg">
+        {{/if}}
+        {{#if favicon_png}}
+        <link rel="shortcut icon" href="{{ path_to_root }}favicon.png">
+        {{/if}}
+        <link rel="stylesheet" href="{{ path_to_root }}css/variables.css">
+        <link rel="stylesheet" href="{{ path_to_root }}css/general.css">
+        <link rel="stylesheet" href="{{ path_to_root }}css/chrome.css">
+        {{#if print_enable}}
+        <link rel="stylesheet" href="{{ path_to_root }}css/print.css" media="print">
+        {{/if}}
+
+        <!-- Fonts -->
+        <link rel="stylesheet" href="{{ path_to_root }}FontAwesome/css/font-awesome.css">
+        {{#if copy_fonts}}
+        <link rel="stylesheet" href="{{ path_to_root }}fonts/fonts.css">
+        {{/if}}
+
+        <!-- Highlight.js Stylesheets -->
+        <link rel="stylesheet" href="{{ path_to_root }}highlight.css">
+        <link rel="stylesheet" href="{{ path_to_root }}tomorrow-night.css">
+        <link rel="stylesheet" href="{{ path_to_root }}ayu-highlight.css">
+
+        <!-- Custom theme stylesheets -->
+        {{#each additional_css}}
+        <link rel="stylesheet" href="{{ ../path_to_root }}{{ this }}">
+        {{/each}}
+
+        {{#if mathjax_support}}
+        <!-- MathJax -->
+        <script async type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
+        {{/if}}
+    </head>
+    <body>
+        <!-- Provide site root to javascript -->
+        <script type="text/javascript">
+            var path_to_root = "{{ path_to_root }}";
+            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "{{ preferred_dark_theme }}" : "{{ default_theme }}";
+        </script>
+
+        <!-- Work around some values being stored in localStorage wrapped in quotes -->
+        <script type="text/javascript">
+            try {
+                var theme = localStorage.getItem('mdbook-theme');
+                var sidebar = localStorage.getItem('mdbook-sidebar');
+
+                if (theme.startsWith('"') && theme.endsWith('"')) {
+                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
+                }
+
+                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
+                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
+                }
+            } catch (e) { }
+        </script>
+
+        <!-- Set the theme before any content is loaded, prevents flash -->
+        <script type="text/javascript">
+            var theme;
+            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
+            if (theme === null || theme === undefined) { theme = default_theme; }
+            var html = document.querySelector('html');
+            html.classList.remove('no-js')
+            html.classList.remove('{{ default_theme }}')
+            html.classList.add(theme);
+            html.classList.add('js');
+        </script>
+
+        <!-- Hide / unhide sidebar before it is displayed -->
+        <script type="text/javascript">
+            var html = document.querySelector('html');
+            var sidebar = 'hidden';
+            if (document.body.clientWidth >= 1080) {
+                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
+                sidebar = sidebar || 'visible';
+            }
+            html.classList.remove('sidebar-visible');
+            html.classList.add("sidebar-" + sidebar);
+        </script>
+
+        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
+            <div class="sidebar-scrollbox">
+                {{#toc}}{{/toc}}
+            </div>
+            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
+        </nav>
+
+        <div id="page-wrapper" class="page-wrapper">
+
+            <div class="page">
+                {{> header}}
+                <div id="menu-bar-hover-placeholder"></div>
+                <div id="menu-bar" class="menu-bar sticky bordered">
+                    <div class="left-buttons">
+                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
+                            <i class="fa fa-bars"></i>
+                        </button>
+                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
+                            <i class="fa fa-paint-brush"></i>
+                        </button>
+                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
+                            <li role="none"><button role="menuitem" class="theme" id="light">{{ theme_option "Light" }}</button></li>
+                            <li role="none"><button role="menuitem" class="theme" id="rust">{{ theme_option "Rust" }}</button></li>
+                            <li role="none"><button role="menuitem" class="theme" id="coal">{{ theme_option "Coal" }}</button></li>
+                            <li role="none"><button role="menuitem" class="theme" id="navy">{{ theme_option "Navy" }}</button></li>
+                            <li role="none"><button role="menuitem" class="theme" id="ayu">{{ theme_option "Ayu" }}</button></li>
+                        </ul>
+                        {{#if search_enabled}}
+                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
+                            <i class="fa fa-search"></i>
+                        </button>
+                        {{/if}}
+                    </div>
+
+                    <h1 class="menu-title">{{ book_title }}</h1>
+
+                    <div class="right-buttons">
+                        {{#if print_enable}}
+                        <a href="{{ path_to_root }}print.html" title="Print this book" aria-label="Print this book">
+                            <i id="print-button" class="fa fa-print"></i>
+                        </a>
+                        {{/if}}
+                        {{#if git_repository_url}}
+                        <a href="{{git_repository_url}}" title="Git repository" aria-label="Git repository">
+                            <i id="git-repository-button" class="fa {{git_repository_icon}}"></i>
+                        </a>
+                        {{/if}}
+                    </div>
+                </div>
+
+                {{#if search_enabled}}
+                <div id="search-wrapper" class="hidden">
+                    <form id="searchbar-outer" class="searchbar-outer">
+                        <input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
+                    </form>
+                    <div id="searchresults-outer" class="searchresults-outer hidden">
+                        <div id="searchresults-header" class="searchresults-header"></div>
+                        <ul id="searchresults">
+                        </ul>
+                    </div>
+                </div>
+                {{/if}}
+
+                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
+                <script type="text/javascript">
+                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
+                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
+                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
+                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
+                    });
+                </script>
+
+                <div id="content" class="content">
+                    <main>
+                        {{{ content }}}
+                    </main>
+
+                    <nav class="nav-wrapper" aria-label="Page navigation">
+                        <!-- Mobile navigation buttons -->
+                        {{#previous}}
+                            <a rel="prev" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
+                                <i class="fa fa-angle-left"></i>
+                            </a>
+                        {{/previous}}
+
+                        {{#next}}
+                            <a rel="next" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
+                                <i class="fa fa-angle-right"></i>
+                            </a>
+                        {{/next}}
+
+                        <div style="clear: both"></div>
+                    </nav>
+                </div>
+            </div>
+
+            <nav class="nav-wide-wrapper" aria-label="Page navigation">
+                {{#previous}}
+                    <a rel="prev" href="{{ path_to_root }}{{link}}" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
+                        <i class="fa fa-angle-left"></i>
+                    </a>
+                {{/previous}}
+
+                {{#next}}
+                    <a rel="next" href="{{ path_to_root }}{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
+                        <i class="fa fa-angle-right"></i>
+                    </a>
+                {{/next}}
+            </nav>
+
+        </div>
+
+        {{#if livereload}}
+        <!-- Livereload script (if served using the cli tool) -->
+        <script type="text/javascript">
+            var socket = new WebSocket("{{{livereload}}}");
+            socket.onmessage = function (event) {
+                if (event.data === "reload") {
+                    socket.close();
+                    location.reload();
+                }
+            };
+
+            window.onbeforeunload = function() {
+                socket.close();
+            }
+        </script>
+        {{/if}}
+
+        {{#if google_analytics}}
+        <!-- Google Analytics Tag -->
+        <script type="text/javascript">
+            var localAddrs = ["localhost", "127.0.0.1", ""];
+
+            // make sure we don't activate google analytics if the developer is
+            // inspecting the book locally...
+            if (localAddrs.indexOf(document.location.hostname) === -1) {
+                (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+                (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+                m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+                })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
+
+                ga('create', '{{google_analytics}}', 'auto');
+                ga('send', 'pageview');
+            }
+        </script>
+        {{/if}}
+
+        {{#if playground_line_numbers}}
+        <script type="text/javascript">
+            window.playground_line_numbers = true;
+        </script>
+        {{/if}}
+
+        {{#if playground_copyable}}
+        <script type="text/javascript">
+            window.playground_copyable = true;
+        </script>
+        {{/if}}
+
+        {{#if playground_js}}
+        <script src="{{ path_to_root }}ace.js" type="text/javascript" charset="utf-8"></script>
+        <script src="{{ path_to_root }}editor.js" type="text/javascript" charset="utf-8"></script>
+        <script src="{{ path_to_root }}editor_mine.js" type="text/javascript" charset="utf-8"></script>
+        <script src="{{ path_to_root }}mode-gwion.js" type="text/javascript" charset="utf-8"></script>
+        <script src="{{ path_to_root }}theme-dawn.js" type="text/javascript" charset="utf-8"></script>
+        <script src="{{ path_to_root }}theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
+        {{/if}}
+
+        {{#if search_js}}
+        <script src="{{ path_to_root }}elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
+        <script src="{{ path_to_root }}mark.min.js" type="text/javascript" charset="utf-8"></script>
+        <script src="{{ path_to_root }}searcher.js" type="text/javascript" charset="utf-8"></script>
+        {{/if}}
+
+        <script src="{{ path_to_root }}clipboard.min.js" type="text/javascript" charset="utf-8"></script>
+        <script src="{{ path_to_root }}highlight.js" type="text/javascript" charset="utf-8"></script>
+        <script src="{{ path_to_root }}book.js" type="text/javascript" charset="utf-8"></script>
+
+        <!-- Custom JS scripts -->
+        {{#each additional_js}}
+        <script type="text/javascript" src="{{ ../path_to_root }}{{this}}"></script>
+        {{/each}}
+
+        {{#if is_print}}
+        {{#if mathjax_support}}
+        <script type="text/javascript">
+        window.addEventListener('load', function() {
+            MathJax.Hub.Register.StartupHook('End', function() {
+                window.setTimeout(window.print, 100);
+            });
+        });
+        </script>
+        {{else}}
+        <script type="text/javascript">
+        window.addEventListener('load', function() {
+            window.setTimeout(window.print, 100);
+        });
+        </script>
+        {{/if}}
+        {{/if}}
+
+    </body>
+</html>