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
boost-title = 3
boost-hierarchy = 2
boost-paragraph = 1
+
+[output.html.playground]
+line-numbers= false
+editable = true
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
```
## 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.
+++ /dev/null
-# Makefile
-
-## Basic operations
-
-## translations
-
-## Docs
## 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
+```
# 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.
## 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
**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) {
<<< 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) {
foreach(b: a)
<<< b >>>;
}
-@```
-@hide make -s forloop5.test
+```
## 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
+```
# 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
+```
```
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
+```
## a simple (commented example)
-@``` function0.gw
+```gwion,editable
#! declare function 'test_function'
#! with return type int
#! taking an int as argument
<<< test_function(0) >>>;
#! or use alternate syntax
<<< 1 => test_function >>>;
-@```
-@hide make -s function0.test
+```
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 {
variadic_test(1);
variadic_test(1, 2);
variadic_test(1, 2, 3);
-@```
-@hide make -s variadic.test
+```
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
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 >>>;
-@```
+```
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;
};
-@```
+```
--- /dev/null
+"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);
--- /dev/null
+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;
+ }
+ });
+}
+)();
target=$(sed 's/docs/src/' <<< $mdfile)
ensure_dir $target
mk_target $mdfile > $target
+# mv $mdfile $target
rm $mdfile
}
fi
else runall
fi
+cp docs/*.js src
--- /dev/null
+"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 });
+ })();
+})();
--- /dev/null
+<!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>