From 20b00cb70d73137acee0cc800f212b0f19e90ce7 Mon Sep 17 00:00:00 2001 From: s-ol Date: Sun, 15 Sep 2019 23:32:55 +0200 Subject: wip zip --- mmm/mmmfs/browser.moon | 4 +-- mmm/mmmfs/fileder.moon | 9 +++--- mmm/mmmfs/zip.moon | 59 +++++++++++++++++++++++++++++++++++++++ render_all.moon | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 mmm/mmmfs/zip.moon create mode 100644 render_all.moon diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index 379537e..f94b62a 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -35,12 +35,12 @@ for convert in *converts table.insert casts, convert class Browser - new: (@root, path='', rehydrate=false) => + new: (@root, path, rehydrate=false) => -- root fileder assert @root, 'root fileder is nil' -- active path - @path = ReactiveVar path + @path = ReactiveVar path or '' -- update URL bar if MODE == 'CLIENT' diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index 0055a88..16eef77 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -95,11 +95,12 @@ class Fileder -- * path - the path to mount at -- * mount_as - dont append own name to path mount: (path, mount_as) => - assert not @path, "mounted twice: #{@path} and now #{path}" + if not mount_as + path ..= @gett 'name: alpha' + + assert not @path or @path == path, "mounted twice: #{@path} and now #{path}" @path = path - if not mount_as - @path ..= @gett 'name: alpha' for child in *@children child\mount @path .. '/' @@ -159,7 +160,7 @@ class Fileder key, conversions = @find want if key - value = apply_conversions conversions, @facets[key], @, key + value = apply_conversions conversions, @facets[key]!, @, key value, key -- like @get, throw if no value or conversion path diff --git a/mmm/mmmfs/zip.moon b/mmm/mmmfs/zip.moon new file mode 100644 index 0000000..c6417e2 --- /dev/null +++ b/mmm/mmmfs/zip.moon @@ -0,0 +1,59 @@ +require = relative ..., 1 +import Fileder, Key from require '.fileder' +zip = require 'brimworks.zip' + +-- split filename into dirname + basename +dir_base = (path) -> + dir, base = path\match '(.-)([^/]-)$' + if dir and #dir > 0 + dir = dir\sub 1, #dir - 1 + + dir, base + +-- insert into array unless contained +table_add = (tbl, entry) -> + for _, v in ipairs tbl + if v == entry + return + + table.insert tbl, entry + +-- strip facet formatting +load_facet = (filename) -> + key = (filename\match '(.*)%.%w+') or filename + key = Key key\gsub '%$', '/' + key.filename = filename + + key + +load_tree = (file='root.zip') -> + archive = zip.open file + + fileders = setmetatable {}, + __index: (path) => + with val = Fileder {} + .path = path + rawset @, path, val + + fileders['/root'].facets['name: alpha'] = -> 'root' + + for i = 1, #archive + { :name, :size } = archive\stat i + + path, facet = dir_base "/#{name}" + parent, name = dir_base path + + key = load_facet facet + + this = fileders[path] + this.facets['name: alpha'] = -> name + this.facets[key] = -> + file = archive\open i + with file\read size + file\close! + + table_add fileders[parent].children, this + + fileders['/root'] + +{ :load_tree } diff --git a/render_all.moon b/render_all.moon new file mode 100644 index 0000000..3d295c9 --- /dev/null +++ b/render_all.moon @@ -0,0 +1,76 @@ +add = (tmpl) -> + package.path ..= ";#{tmpl}.lua" + package.moonpath ..= ";#{tmpl}.moon" + +add '?' +add '?.server' +add '?/init' +add '?/init.server' + +require 'mmm' +import tohtml from require 'mmm.component' +import Browser from require 'mmm.mmmfs.browser' +import load_tree from require 'mmm.mmmfs.zip' +import get_meta, header, footer from require 'build.layout' + +export BROWSER + +render = (fileder, output) -> + BROWSER = Browser fileder + + with io.open output, 'w' + \write [[ + + + + + + + + ]] + \write " + #{get_meta fileder} + + + #{header} + + #{assert (tohtml BROWSER), "couldn't render BROWSER"} + + #{footer} + " + \write [[ + + + + + + + + ]] + \write " + + + + " + \close! + +for fileder in coroutine.wrap load_tree!\iterate + print "rendering '#{fileder.path}'..." + os.execute "mkdir -p 'out/#{fileder.path}'" + render fileder, "out/#{fileder.path}/index.html" -- cgit v1.2.3 From 911ac978f7a70997637fcc5dcfe898eef4e11de9 Mon Sep 17 00:00:00 2001 From: s-ol Date: Sat, 28 Sep 2019 16:42:49 +0200 Subject: initial sqlite support --- mmm/mmmfs/drivers/sql.moon | 157 +++++++++++++++++++++++++++++++++++++++++++++ mmm/mmmfs/fileder.moon | 2 +- tests/test_backend.moon | 49 ++++++++++++++ tup.config | 2 +- 4 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 mmm/mmmfs/drivers/sql.moon create mode 100644 tests/test_backend.moon diff --git a/mmm/mmmfs/drivers/sql.moon b/mmm/mmmfs/drivers/sql.moon new file mode 100644 index 0000000..cfe60e6 --- /dev/null +++ b/mmm/mmmfs/drivers/sql.moon @@ -0,0 +1,157 @@ +sqlite = require 'sqlite3' + +class TreeStore + new: (name='db.sqlite3') => + @db = sqlite.open name + + assert @db\exec [[ + PRAGMA foreign_keys = ON; + CREATE TABLE IF NOT EXISTS fileder ( + id INTEGER NOT NULL PRIMARY KEY, + path TEXT NOT NULL UNIQUE, + parent TEXT + ); + CREATE TABLE IF NOT EXISTS facet ( + fileder_id INTEGER NOT NULL + REFERENCES fileder + ON UPDATE CASCADE + ON DELETE CASCADE, + name TEXT, + type TEXT, + value BLOB, + PRIMARY KEY (name, type) + ); + CREATE INDEX IF NOT EXISTS facet_fileder_id ON facet(fileder_id); + CREATE INDEX IF NOT EXISTS facet_name ON facet(name); + ]] + + close: => + @db\close! + + fetch: (q, ...) => + stmt = assert @db\prepare q + stmt\bind ... + stmt\irows! + + fetch_one: (q, ...) => + stmt = assert @db\prepare q + stmt\bind ... + stmt\first_irow! + + exec: (q, ...) => + stmt = assert @db\prepare q + stmt\bind ... + assert stmt\exec! + + -- fileders + list_fileders: (path, recursive=false) => + coroutine.wrap -> + for { path } in @fetch 'SELECT path + FROM fileder WHERE parent = ?', path + coroutine.yield path + if recursive + for p in @list_fileders path + coroutine.yield p + + create_fileder: (parent, name) => + @exec 'INSERT INTO fileder (path, parent) + VALUES (:path, :parent)', + { path: "#{parent}/#{name}", :parent } + + remove_fileder: (path) => + @exec 'DELETE FROM fileder + WHERE path = ?', path + + rename_fileder: (path, next_name) => + @exec 'UPDATE fileder + SET path = CONCAT(parent, "/", :next_name) + WHERE path = :path', + { :path, :next_name } + -- @TODO: rename all children, child-children... + + move_fileder: (path, new_path) => + error '@TODO: implement move_fileder' + + -- facets + list_facets: (path) => + coroutine.wrap -> + for { name, type } in @fetch 'SELECT facet.name, facet.type + FROM facet + INNER JOIN fileder ON facet.fileder_id = fileder.id + WHERE fileder.path = ?', path + coroutine.yield name, type + + load_facet: (path, name, type) => + v = @fetch_one 'SELECT facet.value + FROM facet + INNER JOIN fileder ON facet.fileder_id = fileder.id + WHERE fileder.path = :path + AND facet.name = :name + AND facet.type = :type', + { :path, :name, :type } + v[1] + + create_facet: (path, name, type, blob) => + @exec 'INSERT INTO facet (fileder_id, name, type, value) + SELECT id, :name, :type, :blob + FROM fileder + WHERE fileder.path = :path', + { :path, :name, :type, :blob } + + remove_facet: (path, name, type) => + @exec 'DELETE FROM facet + WHERE name = :name + AND type = :type + AND fileder_id = (SELECT id FROM fileder WHERE path = :path)', + { :path, :name, :type } + + rename_facet: (path, name, type, next_name) => + @exec 'UPDATE facet + SET name = :next_name + WHERE name = :name + AND type = :type + AND fileder_id = (SELECT id FROM fileder WHERE path = :path)', + { :path, :name, :next_name, :type } + + update_facet: (path, name, type, blob) => + @exec 'UPDATE facet + SET value = :blob + WHERE facet.name = :name + AND facet.type = :type + AND facet.fileder_id = (SELECT id FROM fileder WHERE path = :path)', + { :path, :name, :type, :blob } + +load_tree = (file='root.zip') -> + archive = zip.open file + + fileders = setmetatable {}, + __index: (path) => + with val = Fileder {} + .path = path + rawset @, path, val + + fileders['/root'].facets['name: alpha'] = -> 'root' + + for i = 1, #archive + { :name, :size } = archive\stat i + + path, facet = dir_base "/#{name}" + parent, name = dir_base path + + key = load_facet facet + + this = fileders[path] + this.facets['name: alpha'] = -> name + this.facets[key] = -> + file = archive\open i + with file\read size + file\close! + + table_add fileders[parent].children, this + + fileders['/root'] + +{ + :TreeStore, + load_tree, +} diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index 16eef77..0400141 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -160,7 +160,7 @@ class Fileder key, conversions = @find want if key - value = apply_conversions conversions, @facets[key]!, @, key + value = apply_conversions conversions, @facets[key], @, key value, key -- like @get, throw if no value or conversion path diff --git a/tests/test_backend.moon b/tests/test_backend.moon new file mode 100644 index 0000000..d217c47 --- /dev/null +++ b/tests/test_backend.moon @@ -0,0 +1,49 @@ +import TreeStore from require 'mmm.mmmfs.drivers.sql' +ts = TreeStore! + +assert_seq1 = (expected, iter) -> + tbl + i = 0 + + for x in iter + i += 1 + assert expected[i] == x, "entry #{i}: '#{x}', expected '#{expected[i]}'!" + + assert i == #expected, "only #{i} entries found, expected #{#expected}" + +assert_seq2 = (expected, iter) -> + tbl + i = 0 + + for a, b in iter + i += 1 + assert expected[i][1] == a, "entry #{i} a: '#{a}', expected '#{expected[i][1]}'!" + assert expected[i][2] == b, "entry #{i} b: '#{b}', expected '#{expected[i][2]}'!" + + assert i == #expected, "only #{i} entries found, expected #{#expected}" + +assert_seq1 {}, ts\list_fileders '' +assert_seq1 {}, ts\list_fileders '', true + +ts\create_fileder '', 'hello' +ts\create_fileder '/hello', 'world' +assert_seq1 {'/hello', '/hello/world'}, ts\list_fileders '', true + +ts\create_facet '/hello/world', '', 'text/markdown', '# Helau World!' +ts\create_facet '/hello/world', 'nome', 'alpha', 'world' + +assert_seq2 {}, ts\list_facets '/hello' +assert_seq2 { {'', 'text/markdown'}, {'nome', 'alpha'} }, ts\list_facets '/hello/world' + +ts\rename_facet '/hello/world', 'nome', 'alpha', 'name' +assert_seq2 { {'', 'text/markdown'}, {'name', 'alpha'} }, ts\list_facets '/hello/world' + +assert ('# Helau World!' == ts\load_facet '/hello/world', '', 'text/markdown') +ts\update_facet '/hello/world', '', 'text/markdown', '# Hello World!' +assert ('# Hello World!' == ts\load_facet '/hello/world', '', 'text/markdown') + +ts\remove_fileder '/hello/world' +ts\remove_fileder '/hello' + +assert_seq2 {}, ts\list_facets '/hello/world' +assert_seq1 {}, ts\list_fileders '', true diff --git a/tup.config b/tup.config index 7010858..54e707c 100644 --- a/tup.config +++ b/tup.config @@ -1,2 +1,2 @@ CONFIG_FENGARI_VERSION=v0.1.4 -CONFIG_SASS_ARGS=-m auto +CONFIG_SASS_ARGS=-mauto -- cgit v1.2.3 From 7cb951d05eb9f2408ee34f7c5f0b49907a03bbfc Mon Sep 17 00:00:00 2001 From: s-ol Date: Sun, 29 Sep 2019 16:59:00 +0200 Subject: add busted spec for driver --- mmm/mmmfs/drivers/sql.moon | 72 +++++++++++++++++++++++++------------ spec/driver_spec.moon | 88 ++++++++++++++++++++++++++++++++++++++++++++++ tests/test_backend.moon | 49 -------------------------- 3 files changed, 138 insertions(+), 71 deletions(-) create mode 100644 spec/driver_spec.moon delete mode 100644 tests/test_backend.moon diff --git a/mmm/mmmfs/drivers/sql.moon b/mmm/mmmfs/drivers/sql.moon index cfe60e6..a961e1e 100644 --- a/mmm/mmmfs/drivers/sql.moon +++ b/mmm/mmmfs/drivers/sql.moon @@ -2,24 +2,27 @@ sqlite = require 'sqlite3' class TreeStore new: (name='db.sqlite3') => - @db = sqlite.open name + @db = if name then sqlite.open name else sqlite.open_memory! assert @db\exec [[ PRAGMA foreign_keys = ON; + PRAGMA case_sensitive_like = ON; CREATE TABLE IF NOT EXISTS fileder ( id INTEGER NOT NULL PRIMARY KEY, path TEXT NOT NULL UNIQUE, - parent TEXT + parent TEXT REFERENCES fileder(path) + ON DELETE CASCADE + ON UPDATE CASCADE ); CREATE TABLE IF NOT EXISTS facet ( fileder_id INTEGER NOT NULL REFERENCES fileder ON UPDATE CASCADE ON DELETE CASCADE, - name TEXT, - type TEXT, - value BLOB, - PRIMARY KEY (name, type) + name TEXT NOT NULL, + type TEXT NOT NULL, + value BLOB NOT NULL, + PRIMARY KEY (fileder_id, name, type) ); CREATE INDEX IF NOT EXISTS facet_fileder_id ON facet(fileder_id); CREATE INDEX IF NOT EXISTS facet_name ON facet(name); @@ -30,47 +33,60 @@ class TreeStore fetch: (q, ...) => stmt = assert @db\prepare q - stmt\bind ... + stmt\bind ... if 0 < select '#', ... stmt\irows! fetch_one: (q, ...) => stmt = assert @db\prepare q - stmt\bind ... + stmt\bind ... if 0 < select '#', ... stmt\first_irow! exec: (q, ...) => stmt = assert @db\prepare q - stmt\bind ... - assert stmt\exec! + stmt\bind ... if 0 < select '#', ... + res = assert stmt\exec! -- fileders - list_fileders: (path, recursive=false) => + list_fileders_in: (path) => coroutine.wrap -> for { path } in @fetch 'SELECT path - FROM fileder WHERE parent = ?', path + FROM fileder WHERE parent IS ?', path coroutine.yield path - if recursive - for p in @list_fileders path - coroutine.yield p + + list_all_fileders: (path) => + coroutine.wrap -> + for path in @list_fileders_in path + coroutine.yield path + for p in @list_all_fileders path + coroutine.yield p create_fileder: (parent, name) => @exec 'INSERT INTO fileder (path, parent) - VALUES (:path, :parent)', - { path: "#{parent}/#{name}", :parent } + VALUES (IFNULL(:parent, "") || "/" || :name, :parent)', + { :parent, :name } + + changes = @fetch_one 'SELECT changes()' + assert changes[1] == 1, "couldn't create fileder - parent missing?" remove_fileder: (path) => @exec 'DELETE FROM fileder - WHERE path = ?', path + WHERE path LIKE :path || "/%" + OR path = :path', path rename_fileder: (path, next_name) => + error 'not implemented' + @exec 'UPDATE fileder - SET path = CONCAT(parent, "/", :next_name) + SET path = IFNULL(parent, "") || "/" || :next_name WHERE path = :path', { :path, :next_name } + -- @TODO: rename all children, child-children... - move_fileder: (path, new_path) => - error '@TODO: implement move_fileder' + move_fileder: (path, new_parent) => + error 'not implemented' + + -- @TODO: remove all children, child-children... -- facets list_facets: (path) => @@ -89,7 +105,7 @@ class TreeStore AND facet.name = :name AND facet.type = :type', { :path, :name, :type } - v[1] + v and v[1] create_facet: (path, name, type, blob) => @exec 'INSERT INTO facet (fileder_id, name, type, value) @@ -98,6 +114,9 @@ class TreeStore WHERE fileder.path = :path', { :path, :name, :type, :blob } + changes = @fetch_one 'SELECT changes()' + assert changes[1] == 1, "couldn't create facet - fileder missing?" + remove_facet: (path, name, type) => @exec 'DELETE FROM facet WHERE name = :name @@ -105,6 +124,9 @@ class TreeStore AND fileder_id = (SELECT id FROM fileder WHERE path = :path)', { :path, :name, :type } + changes = @fetch_one 'SELECT changes()' + assert changes[1] == 1, "no such facet" + rename_facet: (path, name, type, next_name) => @exec 'UPDATE facet SET name = :next_name @@ -113,6 +135,9 @@ class TreeStore AND fileder_id = (SELECT id FROM fileder WHERE path = :path)', { :path, :name, :next_name, :type } + changes = @fetch_one 'SELECT changes()' + assert changes[1] == 1, "no such facet" + update_facet: (path, name, type, blob) => @exec 'UPDATE facet SET value = :blob @@ -121,6 +146,9 @@ class TreeStore AND facet.fileder_id = (SELECT id FROM fileder WHERE path = :path)', { :path, :name, :type, :blob } + changes = @fetch_one 'SELECT changes()' + assert changes[1] == 1, "no such facet" + load_tree = (file='root.zip') -> archive = zip.open file diff --git a/spec/driver_spec.moon b/spec/driver_spec.moon new file mode 100644 index 0000000..60cd574 --- /dev/null +++ b/spec/driver_spec.moon @@ -0,0 +1,88 @@ +import TreeStore from require 'mmm.mmmfs.drivers.sql' + +sort2 = (a, b) -> + {ax, ay}, {bx, by} = a, b + "#{ax}//#{ay}" < "#{bx}//#{by}" +toseq = (iter) -> with v = [x for x in iter] + table.sort v +toseq2 = (iter) -> with v = [{x, y} for x, y in iter] + table.sort v, sort2 + +describe "sql driver", -> + randomize false + + ts = TreeStore! + + it "starts out empty", -> + assert.are.same {}, toseq ts\list_fileders_in! + assert.are.same {}, toseq ts\list_all_fileders! + + it "can't create fileders without missing parents", -> + assert.has_error -> + ts\create_fileder '/hello', 'world' + + it "can create root fileders", -> + ts\create_fileder nil, 'hello' + assert.are.same {'/hello'}, toseq ts\list_all_fileders! + + it "can create and list child fileders recursively", -> + ts\create_fileder '/hello', 'world' + ts\create_fileder '/hello/world', 'again' + + assert.are.same {'/hello', '/hello/world', '/hello/world/again'}, + toseq ts\list_all_fileders! + + it "can list immediate children", -> + assert.are.same {"/hello"}, toseq ts\list_fileders_in! + assert.are.same {"/hello/world"}, toseq ts\list_fileders_in "/hello" + assert.are.same {"/hello/world/again"}, toseq ts\list_fileders_in "/hello/world" + + describe "can create and list facets", -> + ts\create_facet '/hello', 'name', 'alpha', 'hello' + ts\create_facet '/hello/world', 'name', 'alpha', 'world' + ts\create_facet '/hello/world', '', 'text/markdown', '# Helau World!' + + it "can't create facet for nonexistant fileders", -> + assert.has_error -> ts\create_facet '/hello/orldw', 'name', 'alpha', 'foo' + + it "can't create facet without value", -> + assert.has_error -> ts\create_facet '/hello/world', 'other', 'alpha', nil + + it "can't create facet for duplicate keys", -> + assert.has_error -> ts\create_facet '/hello/world', 'name', 'alpha', 'foo' + + assert.are.same {{'name', 'alpha'}}, toseq2 ts\list_facets '/hello' + assert.are.same {{'', 'text/markdown'}, {'name', 'alpha'}}, + toseq2 ts\list_facets '/hello/world' + + it "can load facets", -> + assert.are.equal 'hello', ts\load_facet '/hello', 'name', 'alpha' + assert.are.equal 'world', ts\load_facet '/hello/world', 'name', 'alpha' + assert.are.equal '# Helau World!', ts\load_facet '/hello/world', '', 'text/markdown' + assert.is_falsy ts\load_facet '/hello', 'nonexistant', 'facet' + + it "can rename facets", -> + ts\rename_facet '/hello/world', 'name', 'alpha', 'gnome' + assert.are.same {{'', 'text/markdown'}, {'gnome', 'alpha'}}, + toseq2 ts\list_facets '/hello/world' + assert.are.equal 'world', ts\load_facet '/hello/world', 'gnome', 'alpha' + + it "can update facets", -> + ts\update_facet '/hello/world', '', 'text/markdown', '# Hello World!' + assert.are.same {{'', 'text/markdown'}, {'gnome', 'alpha'}}, + toseq2 ts\list_facets '/hello/world' + assert.are.equal '# Hello World!', ts\load_facet '/hello/world', '', 'text/markdown' + + it "can remove facets", -> + ts\remove_facet '/hello/world', 'gnome', 'alpha' + assert.are.same {{'', 'text/markdown'}}, toseq2 ts\list_facets '/hello/world' + + assert.has_error -> ts\remove_facet '/hello/world', 'gnome', 'alpha' + + it "can delete fileders", -> + ts\remove_fileder '/hello/world' + assert.is_falsy ts\load_facet '/hello/world', 'gnome', 'alpha' + assert.are.same {'/hello'}, toseq ts\list_all_fileders! + + ts\remove_fileder '/hello' + assert.are.same {}, toseq ts\list_all_fileders! diff --git a/tests/test_backend.moon b/tests/test_backend.moon deleted file mode 100644 index d217c47..0000000 --- a/tests/test_backend.moon +++ /dev/null @@ -1,49 +0,0 @@ -import TreeStore from require 'mmm.mmmfs.drivers.sql' -ts = TreeStore! - -assert_seq1 = (expected, iter) -> - tbl - i = 0 - - for x in iter - i += 1 - assert expected[i] == x, "entry #{i}: '#{x}', expected '#{expected[i]}'!" - - assert i == #expected, "only #{i} entries found, expected #{#expected}" - -assert_seq2 = (expected, iter) -> - tbl - i = 0 - - for a, b in iter - i += 1 - assert expected[i][1] == a, "entry #{i} a: '#{a}', expected '#{expected[i][1]}'!" - assert expected[i][2] == b, "entry #{i} b: '#{b}', expected '#{expected[i][2]}'!" - - assert i == #expected, "only #{i} entries found, expected #{#expected}" - -assert_seq1 {}, ts\list_fileders '' -assert_seq1 {}, ts\list_fileders '', true - -ts\create_fileder '', 'hello' -ts\create_fileder '/hello', 'world' -assert_seq1 {'/hello', '/hello/world'}, ts\list_fileders '', true - -ts\create_facet '/hello/world', '', 'text/markdown', '# Helau World!' -ts\create_facet '/hello/world', 'nome', 'alpha', 'world' - -assert_seq2 {}, ts\list_facets '/hello' -assert_seq2 { {'', 'text/markdown'}, {'nome', 'alpha'} }, ts\list_facets '/hello/world' - -ts\rename_facet '/hello/world', 'nome', 'alpha', 'name' -assert_seq2 { {'', 'text/markdown'}, {'name', 'alpha'} }, ts\list_facets '/hello/world' - -assert ('# Helau World!' == ts\load_facet '/hello/world', '', 'text/markdown') -ts\update_facet '/hello/world', '', 'text/markdown', '# Hello World!' -assert ('# Hello World!' == ts\load_facet '/hello/world', '', 'text/markdown') - -ts\remove_fileder '/hello/world' -ts\remove_fileder '/hello' - -assert_seq2 {}, ts\list_facets '/hello/world' -assert_seq1 {}, ts\list_fileders '', true -- cgit v1.2.3 From 7448fe54c582f1c2535c3a41bfb51ac4e00161a6 Mon Sep 17 00:00:00 2001 From: s-ol Date: Mon, 7 Oct 2019 14:17:58 +0000 Subject: SQL import and loading --- .gitignore | 1 + Tupfile | 10 +++---- Tuprules.lua | 13 -------- import_all.moon | 55 ++++++++++++++++++++++++++++++++++ mmm/mmmfs/drivers/sql.moon | 75 ++++++++++++++++++++++------------------------ mmm/mmmfs/drivers/zip.moon | 59 ++++++++++++++++++++++++++++++++++++ mmm/mmmfs/zip.moon | 59 ------------------------------------ render_all.moon | 42 ++++++++++++++++++++++++-- root/Tupdefault.lua | 31 ------------------- spec/driver_spec.moon | 12 ++++---- 10 files changed, 202 insertions(+), 155 deletions(-) delete mode 100644 Tuprules.lua create mode 100644 import_all.moon create mode 100644 mmm/mmmfs/drivers/zip.moon delete mode 100644 mmm/mmmfs/zip.moon delete mode 100644 root/Tupdefault.lua diff --git a/.gitignore b/.gitignore index 34245b3..26b821c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ dist +out ##### TUP GITIGNORE ##### ##### Lines below automatically generated by Tup. ##### Do not edit. diff --git a/Tupfile b/Tupfile index f3e300b..edb8b62 100644 --- a/Tupfile +++ b/Tupfile @@ -4,12 +4,12 @@ include_rules !sassc = |> ^ SCSS %b^ sassc @(SASS_ARGS) %f %o |> | %o.map # download fengari dependencies -: |> !download |> root/fengari-web.js -: |> !download |> root/fengari-web.js.map -: static/* |> cp %f root/ |> root/%b +: |> !download |> out/fengari-web.js +: |> !download |> out/fengari-web.js.map +: static/* |> cp %f out/ |> out/%b # render stylesheet -: scss/main.scss |> !sassc |> root/main.css +: scss/main.scss |> !sassc |> out/main.css # bundle for client loading -: mmm/.bundle.lua | |> ^ WRAP %d^ moon &(build)/bundle_module.moon %o --wrap %f |> root/mmm.bundle.lua +: mmm/.bundle.lua | |> ^ WRAP %d^ moon &(build)/bundle_module.moon %o --wrap %f |> out/mmm.bundle.lua diff --git a/Tuprules.lua b/Tuprules.lua deleted file mode 100644 index cd711a5..0000000 --- a/Tuprules.lua +++ /dev/null @@ -1,13 +0,0 @@ -tup.creategitignore() - -root = tup.nodevariable '.' -build = tup.nodevariable 'build' - -function lua_path() - local LUA_PATH = {} - LUA_PATH += root .. '/?.lua' - LUA_PATH += root .. '/?.server.lua' - LUA_PATH += root .. '/?/init.lua' - LUA_PATH += root .. '/?/init.server.lua' - return 'LUA_PATH="' .. table.concat(LUA_PATH, ';') .. '"' -end diff --git a/import_all.moon b/import_all.moon new file mode 100644 index 0000000..3a2ac61 --- /dev/null +++ b/import_all.moon @@ -0,0 +1,55 @@ +add = (tmpl) -> + package.path ..= ";#{tmpl}.lua" + package.moonpath ..= ";#{tmpl}.moon" + +add '?' +add '?.server' +add '?/init' +add '?/init.server' + +require 'mmm' +require 'lfs' +import Fileder, Key from require 'mmm.mmmfs.fileder' +import SQLStore from require 'mmm.mmmfs.drivers.sql' + +-- usage: +-- moon import_all.moon +{ root } = arg + +assert root, "please specify the root directory" + +-- load a fs file as a fileder facet +load_facet = (filename, filepath) -> + key = (filename\match '(.*)%.%w+') or filename + key = Key key\gsub '%$', '/' + key.filename = filename + + file = assert (io.open filepath, 'r'), "couldn't open facet file '#{filename}'" + value = file\read '*all' + file\close! + + key, value + + +with SQLStore verbose: true + import_fileder = (fileder, dirpath) -> + for file in lfs.dir dirpath + continue if '.' == file\sub 1, 1 + continue if file == 'Tupdefault.lua' + continue if file == 'index.html' + continue if file == '$order' + + filepath = "#{dirpath}/#{file}" + attr = lfs.attributes filepath + switch attr.mode + when 'file' + key, value = load_facet file, filepath + \create_facet fileder, key.name, key.type, value + when 'directory' + next_fileder = \create_fileder fileder, file + -- \create_facet next_fileder, 'name', 'alpha', file + import_fileder next_fileder, filepath + else + warn "unknown entry type '#{attr.mode}'" + + import_fileder '', root diff --git a/mmm/mmmfs/drivers/sql.moon b/mmm/mmmfs/drivers/sql.moon index a961e1e..514985c 100644 --- a/mmm/mmmfs/drivers/sql.moon +++ b/mmm/mmmfs/drivers/sql.moon @@ -1,8 +1,20 @@ sqlite = require 'sqlite3' -class TreeStore - new: (name='db.sqlite3') => - @db = if name then sqlite.open name else sqlite.open_memory! +class SQLStore + new: (opts = {}) => + opts.name or= 'db.sqlite3' + opts.verbose or= false + opts.memory or= false + + if not opts.verbose + @log = -> + + if opts.memory + @log "opening in-memory DB..." + @db = sqlite.open_memory! + else + @log "opening '#{opts.name}'..." + @db = sqlite.open opts.name assert @db\exec [[ PRAGMA foreign_keys = ON; @@ -14,6 +26,8 @@ class TreeStore ON DELETE CASCADE ON UPDATE CASCADE ); + INSERT OR IGNORE INTO fileder (path, parent) VALUES ("", NULL); + CREATE TABLE IF NOT EXISTS facet ( fileder_id INTEGER NOT NULL REFERENCES fileder @@ -28,6 +42,9 @@ class TreeStore CREATE INDEX IF NOT EXISTS facet_name ON facet(name); ]] + log: (...) => + print "[DB]", ... + close: => @db\close! @@ -47,13 +64,13 @@ class TreeStore res = assert stmt\exec! -- fileders - list_fileders_in: (path) => + list_fileders_in: (path='') => coroutine.wrap -> for { path } in @fetch 'SELECT path FROM fileder WHERE parent IS ?', path coroutine.yield path - list_all_fileders: (path) => + list_all_fileders: (path='') => coroutine.wrap -> for path in @list_fileders_in path coroutine.yield path @@ -61,14 +78,19 @@ class TreeStore coroutine.yield p create_fileder: (parent, name) => + path = "#{parent}/#{name}" + + @log "creating fileder #{path}" @exec 'INSERT INTO fileder (path, parent) - VALUES (IFNULL(:parent, "") || "/" || :name, :parent)', - { :parent, :name } + VALUES (:path, :parent)', + { :path, :parent } changes = @fetch_one 'SELECT changes()' assert changes[1] == 1, "couldn't create fileder - parent missing?" + path remove_fileder: (path) => + @log "removing fileder #{path}" @exec 'DELETE FROM fileder WHERE path LIKE :path || "/%" OR path = :path', path @@ -77,7 +99,7 @@ class TreeStore error 'not implemented' @exec 'UPDATE fileder - SET path = IFNULL(parent, "") || "/" || :next_name + SET path = parent || "/" || :next_name WHERE path = :path', { :path, :next_name } @@ -108,6 +130,7 @@ class TreeStore v and v[1] create_facet: (path, name, type, blob) => + @log "creating facet #{path} | #{name}: #{type}" @exec 'INSERT INTO facet (fileder_id, name, type, value) SELECT id, :name, :type, :blob FROM fileder @@ -118,6 +141,7 @@ class TreeStore assert changes[1] == 1, "couldn't create facet - fileder missing?" remove_facet: (path, name, type) => + @log "removing facet #{path} | #{name}: #{type}" @exec 'DELETE FROM facet WHERE name = :name AND type = :type @@ -128,6 +152,7 @@ class TreeStore assert changes[1] == 1, "no such facet" rename_facet: (path, name, type, next_name) => + @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}" @exec 'UPDATE facet SET name = :next_name WHERE name = :name @@ -139,6 +164,7 @@ class TreeStore assert changes[1] == 1, "no such facet" update_facet: (path, name, type, blob) => + @log "updating facet #{path} | #{name}: #{type}" @exec 'UPDATE facet SET value = :blob WHERE facet.name = :name @@ -149,37 +175,6 @@ class TreeStore changes = @fetch_one 'SELECT changes()' assert changes[1] == 1, "no such facet" -load_tree = (file='root.zip') -> - archive = zip.open file - - fileders = setmetatable {}, - __index: (path) => - with val = Fileder {} - .path = path - rawset @, path, val - - fileders['/root'].facets['name: alpha'] = -> 'root' - - for i = 1, #archive - { :name, :size } = archive\stat i - - path, facet = dir_base "/#{name}" - parent, name = dir_base path - - key = load_facet facet - - this = fileders[path] - this.facets['name: alpha'] = -> name - this.facets[key] = -> - file = archive\open i - with file\read size - file\close! - - table_add fileders[parent].children, this - - fileders['/root'] - { - :TreeStore, - load_tree, + :SQLStore } diff --git a/mmm/mmmfs/drivers/zip.moon b/mmm/mmmfs/drivers/zip.moon new file mode 100644 index 0000000..c6417e2 --- /dev/null +++ b/mmm/mmmfs/drivers/zip.moon @@ -0,0 +1,59 @@ +require = relative ..., 1 +import Fileder, Key from require '.fileder' +zip = require 'brimworks.zip' + +-- split filename into dirname + basename +dir_base = (path) -> + dir, base = path\match '(.-)([^/]-)$' + if dir and #dir > 0 + dir = dir\sub 1, #dir - 1 + + dir, base + +-- insert into array unless contained +table_add = (tbl, entry) -> + for _, v in ipairs tbl + if v == entry + return + + table.insert tbl, entry + +-- strip facet formatting +load_facet = (filename) -> + key = (filename\match '(.*)%.%w+') or filename + key = Key key\gsub '%$', '/' + key.filename = filename + + key + +load_tree = (file='root.zip') -> + archive = zip.open file + + fileders = setmetatable {}, + __index: (path) => + with val = Fileder {} + .path = path + rawset @, path, val + + fileders['/root'].facets['name: alpha'] = -> 'root' + + for i = 1, #archive + { :name, :size } = archive\stat i + + path, facet = dir_base "/#{name}" + parent, name = dir_base path + + key = load_facet facet + + this = fileders[path] + this.facets['name: alpha'] = -> name + this.facets[key] = -> + file = archive\open i + with file\read size + file\close! + + table_add fileders[parent].children, this + + fileders['/root'] + +{ :load_tree } diff --git a/mmm/mmmfs/zip.moon b/mmm/mmmfs/zip.moon deleted file mode 100644 index c6417e2..0000000 --- a/mmm/mmmfs/zip.moon +++ /dev/null @@ -1,59 +0,0 @@ -require = relative ..., 1 -import Fileder, Key from require '.fileder' -zip = require 'brimworks.zip' - --- split filename into dirname + basename -dir_base = (path) -> - dir, base = path\match '(.-)([^/]-)$' - if dir and #dir > 0 - dir = dir\sub 1, #dir - 1 - - dir, base - --- insert into array unless contained -table_add = (tbl, entry) -> - for _, v in ipairs tbl - if v == entry - return - - table.insert tbl, entry - --- strip facet formatting -load_facet = (filename) -> - key = (filename\match '(.*)%.%w+') or filename - key = Key key\gsub '%$', '/' - key.filename = filename - - key - -load_tree = (file='root.zip') -> - archive = zip.open file - - fileders = setmetatable {}, - __index: (path) => - with val = Fileder {} - .path = path - rawset @, path, val - - fileders['/root'].facets['name: alpha'] = -> 'root' - - for i = 1, #archive - { :name, :size } = archive\stat i - - path, facet = dir_base "/#{name}" - parent, name = dir_base path - - key = load_facet facet - - this = fileders[path] - this.facets['name: alpha'] = -> name - this.facets[key] = -> - file = archive\open i - with file\read size - file\close! - - table_add fileders[parent].children, this - - fileders['/root'] - -{ :load_tree } diff --git a/render_all.moon b/render_all.moon index 3d295c9..e2f171e 100644 --- a/render_all.moon +++ b/render_all.moon @@ -10,7 +10,6 @@ add '?/init.server' require 'mmm' import tohtml from require 'mmm.component' import Browser from require 'mmm.mmmfs.browser' -import load_tree from require 'mmm.mmmfs.zip' import get_meta, header, footer from require 'build.layout' export BROWSER @@ -70,7 +69,46 @@ render = (fileder, output) -> " \close! -for fileder in coroutine.wrap load_tree!\iterate +import SQLStore from require 'mmm.mmmfs.drivers.sql' +import Fileder, Key from require 'mmm.mmmfs.fileder' + +-- split filename into dirname + basename +dir_base = (path) -> + dir, base = path\match '(.-)([^/]-)$' + if dir and #dir > 0 + dir = dir\sub 1, #dir - 1 + + dir, base + +load_tree = (store, root='') -> + fileders = setmetatable {}, + __index: (path) => + with val = Fileder {} + .path = path + rawset @, path, val + + root = fileders[root] + root.facets['name: alpha'] = '' + for fn, ft in store\list_facets root.path + val = store\load_facet root.path, fn, ft + root.facets[Key fn, ft] = val + + for path in store\list_all_fileders root.path + fileder = fileders[path] + + parent, name = dir_base path + fileder.facets['name: alpha'] = name + table.insert fileders[parent].children, fileder + + for fn, ft in store\list_facets path + val = store\load_facet path, fn, ft + fileder.facets[Key fn, ft] = val + + root + +tree = load_tree SQLStore! + +for fileder in coroutine.wrap tree\iterate print "rendering '#{fileder.path}'..." os.execute "mkdir -p 'out/#{fileder.path}'" render fileder, "out/#{fileder.path}/index.html" diff --git a/root/Tupdefault.lua b/root/Tupdefault.lua deleted file mode 100644 index 260ca2e..0000000 --- a/root/Tupdefault.lua +++ /dev/null @@ -1,31 +0,0 @@ -local LUA_PATH = lua_path() -bundle = LUA_PATH .. ' moon ' .. build .. '/bundle_fileder.moon' -render = LUA_PATH .. ' moon ' .. build .. '/render_fileder.moon' - -local _facets, facets = {}, {} -for i, file in ipairs(tup.glob '*$*') do _facets[file] = true end -for i, file in ipairs(tup.glob '*:*') do _facets[file] = true end -for i, file in ipairs(tup.glob '*->*') do _facets[file] = true end - -for file in pairs(_facets) do facets += file end -table.sort(facets) - -local inputs = '' -for i, file in ipairs(facets) do - inputs = inputs .. " '" .. file .. "'" -end - -facets += '' -facets += root .. '/' - -tup.rule( - facets, - '^ BNDL %d^ ' .. bundle .. ' ' .. root .. ' %d ' .. inputs .. ' -- %', - { '$bundle.lua', '../' } -) - -tup.rule( - '$bundle.lua', - '^ HTML %d^ ' .. render .. ' ' .. root, - 'index.html' -) diff --git a/spec/driver_spec.moon b/spec/driver_spec.moon index 60cd574..379dcac 100644 --- a/spec/driver_spec.moon +++ b/spec/driver_spec.moon @@ -1,4 +1,4 @@ -import TreeStore from require 'mmm.mmmfs.drivers.sql' +import SQLStore from require 'mmm.mmmfs.drivers.sql' sort2 = (a, b) -> {ax, ay}, {bx, by} = a, b @@ -11,7 +11,7 @@ toseq2 = (iter) -> with v = [{x, y} for x, y in iter] describe "sql driver", -> randomize false - ts = TreeStore! + ts = SQLStore memory: true it "starts out empty", -> assert.are.same {}, toseq ts\list_fileders_in! @@ -22,12 +22,14 @@ describe "sql driver", -> ts\create_fileder '/hello', 'world' it "can create root fileders", -> - ts\create_fileder nil, 'hello' + assert.are.same '/hello', ts\create_fileder '', 'hello' assert.are.same {'/hello'}, toseq ts\list_all_fileders! it "can create and list child fileders recursively", -> - ts\create_fileder '/hello', 'world' - ts\create_fileder '/hello/world', 'again' + assert.are.same '/hello/world', + ts\create_fileder '/hello', 'world' + assert.are.same '/hello/world/again', + ts\create_fileder '/hello/world', 'again' assert.are.same {'/hello', '/hello/world', '/hello/world/again'}, toseq ts\list_all_fileders! -- cgit v1.2.3 From 5e145f9607a52d0911e1101f6f906d965499f909 Mon Sep 17 00:00:00 2001 From: s-ol Date: Mon, 7 Oct 2019 14:56:32 +0000 Subject: clean up a little --- .gitignore | 1 + build/bundle_fileder.moon | 155 ---------------------------------------------- build/import_all.moon | 55 ++++++++++++++++ build/render_all.moon | 114 ++++++++++++++++++++++++++++++++++ build/render_fileder.moon | 93 ---------------------------- import_all.moon | 55 ---------------- render_all.moon | 114 ---------------------------------- 7 files changed, 170 insertions(+), 417 deletions(-) delete mode 100644 build/bundle_fileder.moon create mode 100644 build/import_all.moon create mode 100644 build/render_all.moon delete mode 100644 build/render_fileder.moon delete mode 100644 import_all.moon delete mode 100644 render_all.moon diff --git a/.gitignore b/.gitignore index 26b821c..352e83e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ dist out +db.sqlite3 ##### TUP GITIGNORE ##### ##### Lines below automatically generated by Tup. ##### Do not edit. diff --git a/build/bundle_fileder.moon b/build/bundle_fileder.moon deleted file mode 100644 index c9f8c35..0000000 --- a/build/bundle_fileder.moon +++ /dev/null @@ -1,155 +0,0 @@ -require 'mmm' -import get_path from require 'build.util' -import Fileder, Key from require 'mmm.mmmfs.fileder' -import opairs from require 'mmm.ordered' -import to_lua from require 'moonscript.base' - --- usage: --- moon bundle_fileder.moon ... -- ... -{ path_to_root, dirname } = arg - -assert path_to_root, "please specify the relative root path" -assert dirname, "please specify the fileder dirname" -path = get_path path_to_root - -facets = {} -children_bundles = {} - -do - addto = facets - for file in *arg[3,] - continue if file == 'Tupdefault.lua' - - if file == '--' - addto = children_bundles - continue - table.insert addto, file - --- load a fs file as a fileder facet -load_facet = (filename) -> - key = (filename\match '(.*)%.%w+') or filename - key = Key key\gsub '%$', '/' - key.filename = filename - - file = assert (io.open filename, 'r'), "couldn't open facet file '#{filename}'" - value = file\read '*all' - file\close! - - key, value - --- escape a string for lua aparser -escape = (str) -> string.format '%q', tostring str - --- dump a fileder subtree as Lua source -dump_fileder = do - _dump = (fileder, root=false) -> - code = "Fileder {" - - for key, val in pairs fileder.facets - if key.original - key = "fromcache(#{escape key}, #{escape key.original})" - else - key = escape key - code ..= "\n[#{key}] = #{escape val}," - - for child in *fileder.children - code ..= "\n#{_dump child}," - - code ..= "\n}" - code - - - (fileder) -> " -local mmmfs = require 'mmm.mmmfs' -local Key, Fileder = mmmfs.Key, mmmfs.Fileder -local function fromcache(str, orig) - local key = Key(str) - key.original = Key(orig) - return key -end - -return #{_dump fileder, true} - " - -renders = { - { - inp: '^text/moonscript %-> (.*)' - out: 'text/lua -> %1' - render: (val, fileder, old, new) -> - lua, err = to_lua val - - if not lua - error "Error compiling #{old}: #{err}" - - "-- this moonscript facet has been transpiled to --- '#{new}' for execution in the browser. --- refer to the original facet as the source. -#{lua}" - }, - { - inp: '^image/' - out: 'URL -> %0' - render: (val, fileder, old, new) -> "#{fileder.path}/#{old.filename}", "[binary removed]" - }, - { - inp: '^video/' - out: 'URL -> %0' - render: (val, fileder, old, new) -> "#{fileder.path}/#{old.filename}", "[binary removed]" - }, -} - -with io.open '$bundle.lua', 'w' - \write dump_fileder with fileder = Fileder 'name: alpha': dirname - \mount path, true - - order = nil - children = {} - - for facet in *facets - if facet == '$order' - order = [line for line in io.lines facet] - continue - key, value = load_facet facet - .facets[key] = value - - extra_facets = {} - for key, value in pairs .facets - for { :inp, :out, :render } in *renders - continue unless key.type\match inp - - built_key = Key key.name, key.type\gsub inp, out - built_key.original = key - - -- dont overwrite existing keys - continue if \has built_key - - rendered, replace = render value, fileder, key, built_key - - extra_facets[built_key] = rendered - .facets[key] = replace if replace - - break - - for k,v in pairs extra_facets - .facets[k] = v - - for child in *children_bundles - -- @BUG: child bundles are malformed due to Tup bug ($ symbol) - child = child\gsub '/%.lua$', '/$bundle.lua' - - dirname = assert child\match '^([%w-_%.]+)/%$bundle%.lua$' - children[dirname] = dofile child - - if order - -- order from order file - for i, name in pairs order - child = assert children[name], "child in $order but not fs: #{name}" - table.insert .children, child - children[name] = nil - - -- sort remainder alphabeticalally - for name, child in opairs children - table.insert .children, child - warn "child #{name} not in $order!" if order - - \close! diff --git a/build/import_all.moon b/build/import_all.moon new file mode 100644 index 0000000..3a2ac61 --- /dev/null +++ b/build/import_all.moon @@ -0,0 +1,55 @@ +add = (tmpl) -> + package.path ..= ";#{tmpl}.lua" + package.moonpath ..= ";#{tmpl}.moon" + +add '?' +add '?.server' +add '?/init' +add '?/init.server' + +require 'mmm' +require 'lfs' +import Fileder, Key from require 'mmm.mmmfs.fileder' +import SQLStore from require 'mmm.mmmfs.drivers.sql' + +-- usage: +-- moon import_all.moon +{ root } = arg + +assert root, "please specify the root directory" + +-- load a fs file as a fileder facet +load_facet = (filename, filepath) -> + key = (filename\match '(.*)%.%w+') or filename + key = Key key\gsub '%$', '/' + key.filename = filename + + file = assert (io.open filepath, 'r'), "couldn't open facet file '#{filename}'" + value = file\read '*all' + file\close! + + key, value + + +with SQLStore verbose: true + import_fileder = (fileder, dirpath) -> + for file in lfs.dir dirpath + continue if '.' == file\sub 1, 1 + continue if file == 'Tupdefault.lua' + continue if file == 'index.html' + continue if file == '$order' + + filepath = "#{dirpath}/#{file}" + attr = lfs.attributes filepath + switch attr.mode + when 'file' + key, value = load_facet file, filepath + \create_facet fileder, key.name, key.type, value + when 'directory' + next_fileder = \create_fileder fileder, file + -- \create_facet next_fileder, 'name', 'alpha', file + import_fileder next_fileder, filepath + else + warn "unknown entry type '#{attr.mode}'" + + import_fileder '', root diff --git a/build/render_all.moon b/build/render_all.moon new file mode 100644 index 0000000..e2f171e --- /dev/null +++ b/build/render_all.moon @@ -0,0 +1,114 @@ +add = (tmpl) -> + package.path ..= ";#{tmpl}.lua" + package.moonpath ..= ";#{tmpl}.moon" + +add '?' +add '?.server' +add '?/init' +add '?/init.server' + +require 'mmm' +import tohtml from require 'mmm.component' +import Browser from require 'mmm.mmmfs.browser' +import get_meta, header, footer from require 'build.layout' + +export BROWSER + +render = (fileder, output) -> + BROWSER = Browser fileder + + with io.open output, 'w' + \write [[ + + + + + + + + ]] + \write " + #{get_meta fileder} + + + #{header} + + #{assert (tohtml BROWSER), "couldn't render BROWSER"} + + #{footer} + " + \write [[ + + + + + + + + ]] + \write " + + + + " + \close! + +import SQLStore from require 'mmm.mmmfs.drivers.sql' +import Fileder, Key from require 'mmm.mmmfs.fileder' + +-- split filename into dirname + basename +dir_base = (path) -> + dir, base = path\match '(.-)([^/]-)$' + if dir and #dir > 0 + dir = dir\sub 1, #dir - 1 + + dir, base + +load_tree = (store, root='') -> + fileders = setmetatable {}, + __index: (path) => + with val = Fileder {} + .path = path + rawset @, path, val + + root = fileders[root] + root.facets['name: alpha'] = '' + for fn, ft in store\list_facets root.path + val = store\load_facet root.path, fn, ft + root.facets[Key fn, ft] = val + + for path in store\list_all_fileders root.path + fileder = fileders[path] + + parent, name = dir_base path + fileder.facets['name: alpha'] = name + table.insert fileders[parent].children, fileder + + for fn, ft in store\list_facets path + val = store\load_facet path, fn, ft + fileder.facets[Key fn, ft] = val + + root + +tree = load_tree SQLStore! + +for fileder in coroutine.wrap tree\iterate + print "rendering '#{fileder.path}'..." + os.execute "mkdir -p 'out/#{fileder.path}'" + render fileder, "out/#{fileder.path}/index.html" diff --git a/build/render_fileder.moon b/build/render_fileder.moon deleted file mode 100644 index 76c7856..0000000 --- a/build/render_fileder.moon +++ /dev/null @@ -1,93 +0,0 @@ -require 'mmm' -import get_path from require 'build.util' -import tohtml from require 'mmm.component' -import Browser from require 'mmm.mmmfs.browser' -import get_meta, header, footer from require 'build.layout' - -export BROWSER - --- usage: --- moon render.moon -{ path_to_root } = arg - -assert path_to_root, "please specify the relative root path" -path = get_path path_to_root - -do - seed = (str) -> - len = #str - rnd = -> math.ceil math.random! * len - - math.randomseed len - - return if len == 0 - - upper, lower = 0, 0 - for i=1,4 - upper += str\byte rnd! - upper *= 0x100 - - lower += str\byte rnd! - lower *= 0x100 - - math.randomseed upper, lower - - seed path - -root = dofile '$bundle.lua' -assert root, "couldn't load $bundle.lua" -root\mount path, true - -BROWSER = Browser root, path - -with io.open 'index.html', 'w' - \write [[ - - - - - - - - ]] - \write " - #{get_meta root} - - - #{header} - - #{assert (tohtml BROWSER), "couldn't render BROWSER"} - - #{footer} - " - \write [[ - - - - - - - - ]] - \write " - - - - " - \close! diff --git a/import_all.moon b/import_all.moon deleted file mode 100644 index 3a2ac61..0000000 --- a/import_all.moon +++ /dev/null @@ -1,55 +0,0 @@ -add = (tmpl) -> - package.path ..= ";#{tmpl}.lua" - package.moonpath ..= ";#{tmpl}.moon" - -add '?' -add '?.server' -add '?/init' -add '?/init.server' - -require 'mmm' -require 'lfs' -import Fileder, Key from require 'mmm.mmmfs.fileder' -import SQLStore from require 'mmm.mmmfs.drivers.sql' - --- usage: --- moon import_all.moon -{ root } = arg - -assert root, "please specify the root directory" - --- load a fs file as a fileder facet -load_facet = (filename, filepath) -> - key = (filename\match '(.*)%.%w+') or filename - key = Key key\gsub '%$', '/' - key.filename = filename - - file = assert (io.open filepath, 'r'), "couldn't open facet file '#{filename}'" - value = file\read '*all' - file\close! - - key, value - - -with SQLStore verbose: true - import_fileder = (fileder, dirpath) -> - for file in lfs.dir dirpath - continue if '.' == file\sub 1, 1 - continue if file == 'Tupdefault.lua' - continue if file == 'index.html' - continue if file == '$order' - - filepath = "#{dirpath}/#{file}" - attr = lfs.attributes filepath - switch attr.mode - when 'file' - key, value = load_facet file, filepath - \create_facet fileder, key.name, key.type, value - when 'directory' - next_fileder = \create_fileder fileder, file - -- \create_facet next_fileder, 'name', 'alpha', file - import_fileder next_fileder, filepath - else - warn "unknown entry type '#{attr.mode}'" - - import_fileder '', root diff --git a/render_all.moon b/render_all.moon deleted file mode 100644 index e2f171e..0000000 --- a/render_all.moon +++ /dev/null @@ -1,114 +0,0 @@ -add = (tmpl) -> - package.path ..= ";#{tmpl}.lua" - package.moonpath ..= ";#{tmpl}.moon" - -add '?' -add '?.server' -add '?/init' -add '?/init.server' - -require 'mmm' -import tohtml from require 'mmm.component' -import Browser from require 'mmm.mmmfs.browser' -import get_meta, header, footer from require 'build.layout' - -export BROWSER - -render = (fileder, output) -> - BROWSER = Browser fileder - - with io.open output, 'w' - \write [[ - - - - - - - - ]] - \write " - #{get_meta fileder} - - - #{header} - - #{assert (tohtml BROWSER), "couldn't render BROWSER"} - - #{footer} - " - \write [[ - - - - - - - - ]] - \write " - - - - " - \close! - -import SQLStore from require 'mmm.mmmfs.drivers.sql' -import Fileder, Key from require 'mmm.mmmfs.fileder' - --- split filename into dirname + basename -dir_base = (path) -> - dir, base = path\match '(.-)([^/]-)$' - if dir and #dir > 0 - dir = dir\sub 1, #dir - 1 - - dir, base - -load_tree = (store, root='') -> - fileders = setmetatable {}, - __index: (path) => - with val = Fileder {} - .path = path - rawset @, path, val - - root = fileders[root] - root.facets['name: alpha'] = '' - for fn, ft in store\list_facets root.path - val = store\load_facet root.path, fn, ft - root.facets[Key fn, ft] = val - - for path in store\list_all_fileders root.path - fileder = fileders[path] - - parent, name = dir_base path - fileder.facets['name: alpha'] = name - table.insert fileders[parent].children, fileder - - for fn, ft in store\list_facets path - val = store\load_facet path, fn, ft - fileder.facets[Key fn, ft] = val - - root - -tree = load_tree SQLStore! - -for fileder in coroutine.wrap tree\iterate - print "rendering '#{fileder.path}'..." - os.execute "mkdir -p 'out/#{fileder.path}'" - render fileder, "out/#{fileder.path}/index.html" -- cgit v1.2.3 From 894bde0db758f2db03fd43d9fa2cd13a33d20643 Mon Sep 17 00:00:00 2001 From: s-ol Date: Mon, 7 Oct 2019 15:05:00 +0000 Subject: little meta-link updates --- README.md | 14 +++++++- build/import.moon | 55 ++++++++++++++++++++++++++++++ build/import_all.moon | 55 ------------------------------ build/layout.moon | 9 ++--- build/render_all.moon | 6 +++- root/text$moonscript -> fn -> mmm$dom.moon | 2 +- 6 files changed, 79 insertions(+), 62 deletions(-) create mode 100644 build/import.moon delete mode 100644 build/import_all.moon diff --git a/README.md b/README.md index 35cccd4..f687309 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,11 @@ You can build the static content with: $ tup init $ tup -Then, run some kind of HTTP server from within `root`, e.g. with python 3 installed: +Next you can render a sqlite3 mmmfs database using + + $ moon build/render_all.moon db.sqlite3 + +Then, run some kind of HTTP server from within `out`, e.g. with python 3 installed: $ cd root $ python -m http.server @@ -37,6 +41,14 @@ You can do this with the following command: $ tup monitor -f -a +### Dependencies +You will need: + +- [MoonScript][moonscript]: `luarocks install moonscript` +- [lua-sqlite3](https://luarocks.org/modules/moteus/sqlite3): `luarocks install sqlite3` +- [discount](https://luarocks.org/modules/craigb/discount): `luarocks install discount` (requires libmarkdown2) +- [busted](https://olivinelabs.com/busted/): `luarocks install busted` (for testing only) + [moonscript]: https://moonscript.org/ [mmm]: https://mmm.s-ol.nu/ [tup]: https://gittup.org/tup diff --git a/build/import.moon b/build/import.moon new file mode 100644 index 0000000..624b54a --- /dev/null +++ b/build/import.moon @@ -0,0 +1,55 @@ +add = (tmpl) -> + package.path ..= ";#{tmpl}.lua" + package.moonpath ..= ";#{tmpl}.moon" + +add '?' +add '?.server' +add '?/init' +add '?/init.server' + +require 'mmm' +require 'lfs' +import Fileder, Key from require 'mmm.mmmfs.fileder' +import SQLStore from require 'mmm.mmmfs.drivers.sql' + +-- usage: +-- moon import.moon [output.sqlite3] +{ root, output } = arg + +assert root, "please specify the root directory" + +-- load a fs file as a fileder facet +load_facet = (filename, filepath) -> + key = (filename\match '(.*)%.%w+') or filename + key = Key key\gsub '%$', '/' + key.filename = filename + + file = assert (io.open filepath, 'r'), "couldn't open facet file '#{filename}'" + value = file\read '*all' + file\close! + + key, value + + +with SQLStore name: output, verbose: true + import_fileder = (fileder, dirpath) -> + for file in lfs.dir dirpath + continue if '.' == file\sub 1, 1 + continue if file == 'Tupdefault.lua' + continue if file == 'index.html' + continue if file == '$order' + + filepath = "#{dirpath}/#{file}" + attr = lfs.attributes filepath + switch attr.mode + when 'file' + key, value = load_facet file, filepath + \create_facet fileder, key.name, key.type, value + when 'directory' + next_fileder = \create_fileder fileder, file + -- \create_facet next_fileder, 'name', 'alpha', file + import_fileder next_fileder, filepath + else + warn "unknown entry type '#{attr.mode}'" + + import_fileder '', root diff --git a/build/import_all.moon b/build/import_all.moon deleted file mode 100644 index 3a2ac61..0000000 --- a/build/import_all.moon +++ /dev/null @@ -1,55 +0,0 @@ -add = (tmpl) -> - package.path ..= ";#{tmpl}.lua" - package.moonpath ..= ";#{tmpl}.moon" - -add '?' -add '?.server' -add '?/init' -add '?/init.server' - -require 'mmm' -require 'lfs' -import Fileder, Key from require 'mmm.mmmfs.fileder' -import SQLStore from require 'mmm.mmmfs.drivers.sql' - --- usage: --- moon import_all.moon -{ root } = arg - -assert root, "please specify the root directory" - --- load a fs file as a fileder facet -load_facet = (filename, filepath) -> - key = (filename\match '(.*)%.%w+') or filename - key = Key key\gsub '%$', '/' - key.filename = filename - - file = assert (io.open filepath, 'r'), "couldn't open facet file '#{filename}'" - value = file\read '*all' - file\close! - - key, value - - -with SQLStore verbose: true - import_fileder = (fileder, dirpath) -> - for file in lfs.dir dirpath - continue if '.' == file\sub 1, 1 - continue if file == 'Tupdefault.lua' - continue if file == 'index.html' - continue if file == '$order' - - filepath = "#{dirpath}/#{file}" - attr = lfs.attributes filepath - switch attr.mode - when 'file' - key, value = load_facet file, filepath - \create_facet fileder, key.name, key.type, value - when 'directory' - next_fileder = \create_fileder fileder, file - -- \create_facet next_fileder, 'name', 'alpha', file - import_fileder next_fileder, filepath - else - warn "unknown entry type '#{attr.mode}'" - - import_fileder '', root diff --git a/build/layout.moon b/build/layout.moon index 6d6e072..61f93cb 100644 --- a/build/layout.moon +++ b/build/layout.moon @@ -6,11 +6,11 @@ pick = (...) -> i = math.ceil math.random! * num select i, ... - iconlink = (href, src, alt, style) -> a { class: 'iconlink', - :href, target: '_blank', + rel: 'me', + :href, img :src, :alt, :style } @@ -69,8 +69,9 @@ logo = svg { } div { class: 'icons', - iconlink 'https://github.com/s-ol/mmm', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/github.svg', - iconlink 'https://twitter.com/S0lll0s', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/twitter.svg', + iconlink 'https://github.com/s-ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/github.svg', 'github' + iconlink 'https://merveilles.town/@s_ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/mastodon.svg', 'mastodon' + iconlink 'https://twitter.com/S0lll0s', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/twitter.svg', 'twitter' iconlink 'https://webring.xxiivv.com/#random', 'https://webring.xxiivv.com/icon.black.svg', 'webring', { height: '1.3em', 'margin-left': '.3em', 'margin-top': '-0.12em' } } diff --git a/build/render_all.moon b/build/render_all.moon index e2f171e..dfbed27 100644 --- a/build/render_all.moon +++ b/build/render_all.moon @@ -12,6 +12,10 @@ import tohtml from require 'mmm.component' import Browser from require 'mmm.mmmfs.browser' import get_meta, header, footer from require 'build.layout' +-- usage: +-- moon render_all.moon [db.sqlite3] +{ file } = arg + export BROWSER render = (fileder, output) -> @@ -106,7 +110,7 @@ load_tree = (store, root='') -> root -tree = load_tree SQLStore! +tree = load_tree SQLStore :name for fileder in coroutine.wrap tree\iterate print "rendering '#{fileder.path}'..." diff --git a/root/text$moonscript -> fn -> mmm$dom.moon b/root/text$moonscript -> fn -> mmm$dom.moon index 84aed7f..8c06030 100644 --- a/root/text$moonscript -> fn -> mmm$dom.moon +++ b/root/text$moonscript -> fn -> mmm$dom.moon @@ -17,7 +17,7 @@ import link_to from (require 'mmm.mmmfs.util') require 'mmm.dom' '.' br! 'You can find the source code of everything ' - a { 'here', href: 'https://github.com/s-ol/mmm' } + a { 'here', href: 'https://git.s-ol.nu/mmm' } '.' br! 'Most of the inner-workings of this page are documented in ' -- cgit v1.2.3 From 81e143fa8181a6adb58d7fba632bd31a13164410 Mon Sep 17 00:00:00 2001 From: s-ol Date: Mon, 7 Oct 2019 18:56:03 +0200 Subject: add simple HTTP server --- README.md | 1 + build/import.moon | 1 - build/render_all.moon | 36 --------------- build/server.moon | 119 +++++++++++++++++++++++++++++++++++++++++++++++++ build/util.moon | 37 +++++++++++++++ mmm/mmmfs/fileder.moon | 9 ++++ 6 files changed, 166 insertions(+), 37 deletions(-) create mode 100644 build/server.moon diff --git a/README.md b/README.md index f687309..94a7f66 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ You will need: - [MoonScript][moonscript]: `luarocks install moonscript` - [lua-sqlite3](https://luarocks.org/modules/moteus/sqlite3): `luarocks install sqlite3` +- [lua-http](https://github.com/daurnimator/lua-http): `luarocks install http` - [discount](https://luarocks.org/modules/craigb/discount): `luarocks install discount` (requires libmarkdown2) - [busted](https://olivinelabs.com/busted/): `luarocks install busted` (for testing only) diff --git a/build/import.moon b/build/import.moon index 624b54a..b5def43 100644 --- a/build/import.moon +++ b/build/import.moon @@ -30,7 +30,6 @@ load_facet = (filename, filepath) -> key, value - with SQLStore name: output, verbose: true import_fileder = (fileder, dirpath) -> for file in lfs.dir dirpath diff --git a/build/render_all.moon b/build/render_all.moon index dfbed27..14e4cce 100644 --- a/build/render_all.moon +++ b/build/render_all.moon @@ -73,42 +73,6 @@ render = (fileder, output) -> " \close! -import SQLStore from require 'mmm.mmmfs.drivers.sql' -import Fileder, Key from require 'mmm.mmmfs.fileder' - --- split filename into dirname + basename -dir_base = (path) -> - dir, base = path\match '(.-)([^/]-)$' - if dir and #dir > 0 - dir = dir\sub 1, #dir - 1 - - dir, base - -load_tree = (store, root='') -> - fileders = setmetatable {}, - __index: (path) => - with val = Fileder {} - .path = path - rawset @, path, val - - root = fileders[root] - root.facets['name: alpha'] = '' - for fn, ft in store\list_facets root.path - val = store\load_facet root.path, fn, ft - root.facets[Key fn, ft] = val - - for path in store\list_all_fileders root.path - fileder = fileders[path] - - parent, name = dir_base path - fileder.facets['name: alpha'] = name - table.insert fileders[parent].children, fileder - - for fn, ft in store\list_facets path - val = store\load_facet path, fn, ft - fileder.facets[Key fn, ft] = val - - root tree = load_tree SQLStore :name diff --git a/build/server.moon b/build/server.moon new file mode 100644 index 0000000..dd491d3 --- /dev/null +++ b/build/server.moon @@ -0,0 +1,119 @@ +add = (tmpl) -> + package.path ..= ";#{tmpl}.lua" + package.moonpath ..= ";#{tmpl}.moon" + +add '?' +add '?.server' +add '?/init' +add '?/init.server' + +require 'mmm' +import dir_base, load_tree from require 'build.util' +import Key from require 'mmm.mmmfs.fileder' +import SQLStore from require 'mmm.mmmfs.drivers.sql' + +server = require 'http.server' +headers = require 'http.headers' + +tojson = (obj) -> + switch type obj + when 'string' + string.format '%q', obj + when 'table' + if obj[1] or not next obj + "[#{table.concat [tojson c for c in *obj], ','}]" + else + "{#{table.concat ["#{tojson k}: #{tojson v}" for k,v in pairs obj], ', '}}" + when 'number' + tostring obj + when 'boolean' + tostring obj + when nil + 'null' + +class Server + new: (@tree, opts={}) => + opts = {k,v for k,v in pairs opts} + opts.host = 'localhost' unless opts.host + opts.port = 8000 unless opts.port + opts.onstream = @\stream + opts.onerror = @\error + + @server = server.listen opts + + listen: => + assert @server\listen! + + _, ip, port = @server\localname! + print "SV", "running at #{ip}:#{port}" + assert @server\loop! + + handle: (method, path, facet) => + fileder = @tree\walk path + switch method + when 'GET', 'HEAD' + if fileder and facet + -- fileder and facet given + if not fileder\has_facet facet.name + return 404, "facet '#{facet.name}' not found in fileder '#{path}'" + + val = fileder\get facet + if val + 200, val + else + 406, 'cant convert facet' + elseif fileder + -- no facet given + facets = [{k.name, k.type} for k,v in pairs fileder.facets] + children = [f.path for f in *fileder.children] + print facets + print children + contents = tojson :facets, :children + 200, contents + else + -- fileder not found + 404, "fileder '#{path}' not found" + else + 501, 'not implemented' + + stream: (sv, stream) => + req = stream\get_headers! + method = req\get ':method' + path = req\get ':path' + + path, facet = dir_base path + print "'#{path}', '#{facet}'" + facet = if #facet > 0 + facet = '' if facet == ':' + accept = req\get 'mmm-accept' + Key facet, accept or 'text/html' + else + nil + + status, body = @handle method, path, facet + + res = headers.new! + response_type = if status > 299 then 'text/plain' + else if facet then facet.type + else 'text/plain' + res\append ':status', tostring status + res\append 'content-type', response_type + + if method == 'HEAD' + stream\write_headers res, true + else + stream\write_headers res, false + stream\write_chunk body, true + + error: (sv, ctx, op, err, errno) => + msg = "#{op} on #{tostring ctx} failed" + msg = "#{msg}: #{err}" if err + print msg + +-- usage: +-- moon server.moon [db.sqlite3] +{ file } = arg + +tree = load_tree SQLStore :file +server = Server tree +server\listen! diff --git a/build/util.moon b/build/util.moon index b9c9613..92450c7 100644 --- a/build/util.moon +++ b/build/util.moon @@ -1,4 +1,5 @@ require 'lfs' +import Fileder, Key from require 'mmm.mmmfs.fileder' get_path = (root) -> cwd = lfs.currentdir! @@ -11,6 +12,42 @@ get_path = (root) -> path +-- split filename into dirname + basename +dir_base = (path) -> + dir, base = path\match '(.-)([^/]-)$' + if dir and #dir > 0 + dir = dir\sub 1, #dir - 1 + + dir, base + +load_tree = (store, root='') -> + fileders = setmetatable {}, + __index: (path) => + with val = Fileder {} + .path = path + rawset @, path, val + + root = fileders[root] + root.facets['name: alpha'] = '' + for fn, ft in store\list_facets root.path + val = store\load_facet root.path, fn, ft + root.facets[Key fn, ft] = val + + for path in store\list_all_fileders root.path + fileder = fileders[path] + + parent, name = dir_base path + fileder.facets['name: alpha'] = name + table.insert fileders[parent].children, fileder + + for fn, ft in store\list_facets path + val = store\load_facet path, fn, ft + fileder.facets[Key fn, ft] = val + + root + { :get_path + :dir_base + :load_tree } diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index 0400141..87dad78 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -123,6 +123,7 @@ class Fileder [name for name in pairs names] -- check whether a facet is directly available + -- when passing a Key, set type to false to check for name only has: (...) => want = Key ... @@ -132,6 +133,14 @@ class Fileder if key.name == want.name and key.type == want.type return key + -- check whether any facet with that name exists + has_facet: (want) => + for key in pairs @facets + continue if key.original + + if key.name == want + return key + -- find facet and type according to criteria, nil if no value or conversion path -- * ... - arguments like Key find: (...) => -- cgit v1.2.3 From ad26c7c4e374f66a978f9946bbb083377f2224a6 Mon Sep 17 00:00:00 2001 From: s-ol Date: Mon, 7 Oct 2019 19:49:16 +0200 Subject: allow server to render with layout --- build/layout.moon | 108 ------------------- build/render_all.moon | 71 ++---------- build/server.moon | 3 +- mmm/mmmfs/conversion.moon | 262 +------------------------------------------- mmm/mmmfs/converts.moon | 269 ++++++++++++++++++++++++++++++++++++++++++++++ mmm/mmmfs/layout.moon | 166 ++++++++++++++++++++++++++++ 6 files changed, 449 insertions(+), 430 deletions(-) delete mode 100644 build/layout.moon create mode 100644 mmm/mmmfs/converts.moon create mode 100644 mmm/mmmfs/layout.moon diff --git a/build/layout.moon b/build/layout.moon deleted file mode 100644 index 61f93cb..0000000 --- a/build/layout.moon +++ /dev/null @@ -1,108 +0,0 @@ -import header, aside, footer, div, svg, script, g, circle, h1, span, b, a, img from require 'mmm.dom' -import navigate_to from (require 'mmm.mmmfs.util') require 'mmm.dom' - -pick = (...) -> - num = select '#', ... - i = math.ceil math.random! * num - select i, ... - -iconlink = (href, src, alt, style) -> a { - class: 'iconlink', - target: '_blank', - rel: 'me', - :href, - img :src, :alt, :style -} - -logo = svg { - class: 'sun' - viewBox: '-0.75 -1 1.5 2' - xmlns: 'http://www.w3.org/2000/svg' - baseProfile: 'full' - version: '1.1' - - g { - transform: 'translate(0 .18)' - - g { class: 'circle out', circle r: '.6', fill: 'none', 'stroke-width': '.12' } - g { class: 'circle in', circle r: '.2', stroke: 'none' } - } -} - -{ - header: header { - div { - h1 { - logo - span { - span 'mmm', class: 'bold' - '​' - '.s‑ol.nu' - } - } - span "fun stuff with code and wires" - -- pick 'fun', 'cool', 'weird', 'interesting', 'new' - -- pick 'stuff', 'things', 'projects', 'experiments', 'news' - -- "with" - -- pick 'mostly code', 'code and wires', 'silicon', 'electronics' - } - aside { - navigate_to '/about', 'about me' - navigate_to '/games', 'games' - navigate_to '/projects', 'other' - a { - href: 'mailto:s%20[removethis]%20[at]%20s-ol.nu' - 'contact' - script " - var l = document.currentScript.parentElement; - l.href = l.href.replace('%20[at]%20', '@'); - l.href = l.href.replace('%20[removethis]', '') + '?subject=Hey there :)'; - " - } - } - } - footer: footer { - span { - 'made with \xe2\x98\xbd by ' - a 's-ol', href: 'https://twitter.com/S0lll0s' - ", #{os.date '%Y'}" - } - div { - class: 'icons', - iconlink 'https://github.com/s-ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/github.svg', 'github' - iconlink 'https://merveilles.town/@s_ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/mastodon.svg', 'mastodon' - iconlink 'https://twitter.com/S0lll0s', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/twitter.svg', 'twitter' - iconlink 'https://webring.xxiivv.com/#random', 'https://webring.xxiivv.com/icon.black.svg', 'webring', - { height: '1.3em', 'margin-left': '.3em', 'margin-top': '-0.12em' } - } - } - get_meta: => - title = (@get 'title: text/plain') or @gett 'name: alpha' - - l = (str) -> - str = str\gsub '[%s\\n]+$', '' - str\gsub '\\n', ' ' - e = (str) -> string.format '%q', l str - - meta = " - - #{l title} - " - - if page_meta = @get '_meta: mmm/dom' - meta ..= page_meta - else - meta ..= " - - - - - - " - - if desc = @get 'description: text/plain' - meta ..= " - " - - meta -} diff --git a/build/render_all.moon b/build/render_all.moon index 14e4cce..4fe827b 100644 --- a/build/render_all.moon +++ b/build/render_all.moon @@ -10,73 +10,24 @@ add '?/init.server' require 'mmm' import tohtml from require 'mmm.component' import Browser from require 'mmm.mmmfs.browser' -import get_meta, header, footer from require 'build.layout' +import render from require 'mmm.mmmfs.layout' +import SQLStore from require 'mmm.mmmfs.drivers.sql' +import load_tree from require 'build.util' -- usage: --- moon render_all.moon [db.sqlite3] -{ file } = arg +-- moon render_all.moon [db.sqlite3] [startpath] +{ file, startpath } = arg export BROWSER -render = (fileder, output) -> - BROWSER = Browser fileder - - with io.open output, 'w' - \write [[ - - - - - - - - ]] - \write " - #{get_meta fileder} - - - #{header} - - #{assert (tohtml BROWSER), "couldn't render BROWSER"} - - #{footer} - " - \write [[ - - - - - - - - ]] - \write " - - - - " - \close! - - tree = load_tree SQLStore :name +tree = tree\walk startpath if startpath for fileder in coroutine.wrap tree\iterate print "rendering '#{fileder.path}'..." os.execute "mkdir -p 'out/#{fileder.path}'" - render fileder, "out/#{fileder.path}/index.html" + + BROWSER = Browser fileder + with io.open "out/#{fileder.path}/index.html", 'w' + \write render (tohtml BROWSER), fileder + \close! diff --git a/build/server.moon b/build/server.moon index dd491d3..b178636 100644 --- a/build/server.moon +++ b/build/server.moon @@ -82,7 +82,6 @@ class Server path = req\get ':path' path, facet = dir_base path - print "'#{path}', '#{facet}'" facet = if #facet > 0 facet = '' if facet == ':' accept = req\get 'mmm-accept' @@ -95,7 +94,7 @@ class Server res = headers.new! response_type = if status > 299 then 'text/plain' else if facet then facet.type - else 'text/plain' + else 'text/json' res\append ':status', tostring status res\append 'content-type', response_type diff --git a/mmm/mmmfs/conversion.moon b/mmm/mmmfs/conversion.moon index f6ca8c0..54cd680 100644 --- a/mmm/mmmfs/conversion.moon +++ b/mmm/mmmfs/conversion.moon @@ -1,263 +1,5 @@ -import div, code, img, video, blockquote, a, span, source, iframe from require 'mmm.dom' -import find_fileder, link_to, embed from (require 'mmm.mmmfs.util') require 'mmm.dom' -import tohtml from require 'mmm.component' - --- fix JS null values -js_fix = if MODE == 'CLIENT' - (arg) -> - return if arg == js.null - arg - --- limit function to one argument -single = (func) -> (val) -> func val - --- load a chunk using a specific 'load'er -loadwith = (_load) -> (val, fileder, key) -> - func = assert _load val, "#{fileder}##{key}" - func! - --- list of converts --- converts each have --- * inp - input type. can capture subtypes using `(.+)` --- * out - output type. can substitute subtypes from inp with %1, %2 etc. --- * transform - function (val: inp, fileder) -> val: out -converts = { - { - inp: 'fn -> (.+)', - out: '%1', - transform: (val, fileder) -> val fileder - }, - { - inp: 'mmm/component', - out: 'mmm/dom', - transform: single tohtml - }, - { - inp: 'mmm/dom', - out: 'text/html', - transform: (node) -> if MODE == 'SERVER' then node else node.outerHTML - }, - { - inp: 'text/html', - out: 'mmm/dom', - transform: if MODE == 'SERVER' - (html, fileder) -> - html = html\gsub '(.-)', (attrs, text) -> - text = nil if #text == 0 - path = '' - while attrs and attrs != '' - key, val, _attrs = attrs\match '^(%w+)="([^"]-)"%s*(.*)' - if not key - key, _attrs = attrs\match '^(%w+)%s*(.*)$' - val = true - - attrs = _attrs - - switch key - when 'path' then path = val - else warn "unkown attribute '#{key}=\"#{val}\"' in " - - link_to path, text, fileder - - html = html\gsub '(.-)', (attrs, desc) -> - path, facet = '', '' - opts = {} - if #desc != 0 - opts.desc = desc - - while attrs and attrs != '' - key, val, _attrs = attrs\match '^(%w+)="([^"]-)"%s*(.*)' - if not key - key, _attrs = attrs\match '^(%w+)%s*(.*)$' - val = true - - attrs = _attrs - - switch key - when 'path' then path = val - when 'facet' then facet = val - when 'nolink' then opts.nolink = true - when 'inline' then opts.inline = true - else warn "unkown attribute '#{key}=\"#{val}\"' in " - - embed path, facet, fileder, opts - - html - else - (html, fileder) -> - parent = with document\createElement 'div' - .innerHTML = html - - -- copy to iterate safely, HTMLCollections update when nodes are GC'ed - embeds = \getElementsByTagName 'mmm-embed' - embeds = [embeds[i] for i=0, embeds.length - 1] - for element in *embeds - path = js_fix element\getAttribute 'path' - facet = js_fix element\getAttribute 'facet' - nolink = js_fix element\getAttribute 'nolink' - inline = js_fix element\getAttribute 'inline' - desc = js_fix element.innerText - - element\replaceWith embed path or '', facet or '', fileder, { :nolink, :inline, :desc } - - embeds = \getElementsByTagName 'mmm-link' - embeds = [embeds[i] for i=0, embeds.length - 1] - for element in *embeds - text = js_fix element.innerText - path = js_fix element\getAttribute 'path' - - element\replaceWith link_to path or '', text, fileder - - assert 1 == parent.childElementCount, "text/html with more than one child!" - parent.firstElementChild - }, - { - inp: 'text/lua -> (.+)', - out: '%1', - transform: loadwith load or loadstring - }, - { - inp: 'mmm/tpl -> (.+)', - out: '%1', - transform: (source, fileder) -> - source\gsub '{{(.-)}}', (expr) -> - path, facet = expr\match '^([%w%-_%./]*)%+(.*)' - assert path, "couldn't match TPL expression '#{expr}'" - - (find_fileder path, fileder)\gett facet - }, - { - inp: 'time/iso8601-date', - out: 'time/unix', - transform: (val) -> - year, _, month, day = val\match '^%s*(%d%d%d%d)(%-?)([01]%d)%2([0-3]%d)%s*$' - assert year, "failed to parse ISO 8601 date: '#{val}'" - os.time :year, :month, :day - }, - { - inp: 'URL -> twitter/tweet', - out: 'mmm/dom', - transform: (href) -> - id = assert (href\match 'twitter.com/[^/]-/status/(%d*)'), "couldn't parse twitter/tweet URL: '#{href}'" - if MODE == 'CLIENT' - with parent = div! - window.twttr.widgets\createTweet id, parent - else - div blockquote { - class: 'twitter-tweet' - 'data-lang': 'en' - a '(linked tweet)', :href - } - }, - { - inp: 'URL -> youtube/video', - out: 'mmm/dom', - transform: (link) -> - id = link\match 'youtu%.be/([^/]+)' - id or= link\match 'youtube.com/watch.*[?&]v=([^&]+)' - id or= link\match 'youtube.com/[ev]/([^/]+)' - id or= link\match 'youtube.com/embed/([^/]+)' - - assert id, "couldn't parse youtube URL: '#{link}'" - - iframe { - width: 560 - height: 315 - frameborder: 0 - allowfullscreen: true - frameBorder: 0 - src: "//www.youtube.com/embed/#{id}" - } - }, - { - inp: 'URL -> image/.+', - out: 'mmm/dom', - transform: (src, fileder) -> img :src - }, - { - inp: 'URL -> video/.+', - out: 'mmm/dom', - transform: (src) -> - -- @TODO: add parsed MIME type - video (source :src), controls: true, loop: true - }, - { - inp: 'text/plain', - out: 'mmm/dom', - transform: (val) -> span val - }, - { - inp: 'alpha', - out: 'mmm/dom', - transform: single code - }, - { - inp: 'URL -> .*', - out: 'mmm/dom', - transform: single code - }, -} - -if MODE == 'SERVER' - ok, moon = pcall require, 'moonscript.base' - if ok - _load = moon.load or moon.loadstring - table.insert converts, { - inp: 'text/moonscript -> (.+)', - out: '%1', - transform: loadwith moon.load or moon.loadstring - } - - table.insert converts, { - inp: 'text/moonscript -> (.+)', - out: 'text/lua -> %1', - transform: single moon.to_lua - } -else - table.insert converts, { - inp: 'text/javascript -> (.+)', - out: '%1', - transform: (source) -> - f = js.new window.Function, source - f! - } - -do - local markdown - if MODE == 'SERVER' - success, discount = pcall require, 'discount' - if not success - warn "NO MARKDOWN SUPPORT!", discount - - markdown = success and (md) -> - res = assert discount.compile md, 'githubtags' - res.body - else - markdown = window and window.marked and window\marked - - if markdown - table.insert converts, { - inp: 'text/markdown', - out: 'text/html', - transform: (md) -> "
#{markdown md}
" - } - - table.insert converts, { - inp: 'text/markdown%+span', - out: 'mmm/dom', - transform: if MODE == 'SERVER' - (source) -> - html = markdown source - html = html\gsub '^$', '/span>' - else - (source) -> - html = markdown source - html = html\gsub '^%s*

%s*', '' - html = html\gsub '%s*

%s*$', '' - with document\createElement 'span' - .innerHTML = html - } +require = relative ..., 1 +converts = require '.converts' count = (base, pattern='->') -> select 2, base\gsub pattern, '' escape_pattern = (inp) -> "^#{inp\gsub '([-/])', '%%%1'}$" diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon new file mode 100644 index 0000000..f8aad9f --- /dev/null +++ b/mmm/mmmfs/converts.moon @@ -0,0 +1,269 @@ +require = relative ..., 1 +import div, code, img, video, blockquote, a, span, source, iframe from require 'mmm.dom' +import find_fileder, link_to, embed from (require 'mmm.mmmfs.util') require 'mmm.dom' +import render from require '.layout' +import tohtml from require 'mmm.component' + +-- fix JS null values +js_fix = if MODE == 'CLIENT' + (arg) -> + return if arg == js.null + arg + +-- limit function to one argument +single = (func) -> (val) -> func val + +-- load a chunk using a specific 'load'er +loadwith = (_load) -> (val, fileder, key) -> + func = assert _load val, "#{fileder}##{key}" + func! + +-- list of converts +-- converts each have +-- * inp - input type. can capture subtypes using `(.+)` +-- * out - output type. can substitute subtypes from inp with %1, %2 etc. +-- * transform - function (val: inp, fileder) -> val: out +converts = { + { + inp: 'fn -> (.+)', + out: '%1', + transform: (val, fileder) -> val fileder + }, + { + inp: 'mmm/component', + out: 'mmm/dom', + transform: single tohtml + }, + { + inp: 'mmm/dom', + out: 'text/html+frag', + transform: (node) -> if MODE == 'SERVER' then node else node.outerHTML + }, + { + inp: 'text/html%+frag', + out: 'text/html', + transform: (html, fileder) -> render html, fileder + }, + { + inp: 'text/html%+frag', + out: 'mmm/dom', + transform: if MODE == 'SERVER' + (html, fileder) -> + html = html\gsub '(.-)', (attrs, text) -> + text = nil if #text == 0 + path = '' + while attrs and attrs != '' + key, val, _attrs = attrs\match '^(%w+)="([^"]-)"%s*(.*)' + if not key + key, _attrs = attrs\match '^(%w+)%s*(.*)$' + val = true + + attrs = _attrs + + switch key + when 'path' then path = val + else warn "unkown attribute '#{key}=\"#{val}\"' in " + + link_to path, text, fileder + + html = html\gsub '(.-)', (attrs, desc) -> + path, facet = '', '' + opts = {} + if #desc != 0 + opts.desc = desc + + while attrs and attrs != '' + key, val, _attrs = attrs\match '^(%w+)="([^"]-)"%s*(.*)' + if not key + key, _attrs = attrs\match '^(%w+)%s*(.*)$' + val = true + + attrs = _attrs + + switch key + when 'path' then path = val + when 'facet' then facet = val + when 'nolink' then opts.nolink = true + when 'inline' then opts.inline = true + else warn "unkown attribute '#{key}=\"#{val}\"' in " + + embed path, facet, fileder, opts + + html + else + (html, fileder) -> + parent = with document\createElement 'div' + .innerHTML = html + + -- copy to iterate safely, HTMLCollections update when nodes are GC'ed + embeds = \getElementsByTagName 'mmm-embed' + embeds = [embeds[i] for i=0, embeds.length - 1] + for element in *embeds + path = js_fix element\getAttribute 'path' + facet = js_fix element\getAttribute 'facet' + nolink = js_fix element\getAttribute 'nolink' + inline = js_fix element\getAttribute 'inline' + desc = js_fix element.innerText + + element\replaceWith embed path or '', facet or '', fileder, { :nolink, :inline, :desc } + + embeds = \getElementsByTagName 'mmm-link' + embeds = [embeds[i] for i=0, embeds.length - 1] + for element in *embeds + text = js_fix element.innerText + path = js_fix element\getAttribute 'path' + + element\replaceWith link_to path or '', text, fileder + + assert 1 == parent.childElementCount, "text/html with more than one child!" + parent.firstElementChild + }, + { + inp: 'text/lua -> (.+)', + out: '%1', + transform: loadwith load or loadstring + }, + { + inp: 'mmm/tpl -> (.+)', + out: '%1', + transform: (source, fileder) -> + source\gsub '{{(.-)}}', (expr) -> + path, facet = expr\match '^([%w%-_%./]*)%+(.*)' + assert path, "couldn't match TPL expression '#{expr}'" + + (find_fileder path, fileder)\gett facet + }, + { + inp: 'time/iso8601-date', + out: 'time/unix', + transform: (val) -> + year, _, month, day = val\match '^%s*(%d%d%d%d)(%-?)([01]%d)%2([0-3]%d)%s*$' + assert year, "failed to parse ISO 8601 date: '#{val}'" + os.time :year, :month, :day + }, + { + inp: 'URL -> twitter/tweet', + out: 'mmm/dom', + transform: (href) -> + id = assert (href\match 'twitter.com/[^/]-/status/(%d*)'), "couldn't parse twitter/tweet URL: '#{href}'" + if MODE == 'CLIENT' + with parent = div! + window.twttr.widgets\createTweet id, parent + else + div blockquote { + class: 'twitter-tweet' + 'data-lang': 'en' + a '(linked tweet)', :href + } + }, + { + inp: 'URL -> youtube/video', + out: 'mmm/dom', + transform: (link) -> + id = link\match 'youtu%.be/([^/]+)' + id or= link\match 'youtube.com/watch.*[?&]v=([^&]+)' + id or= link\match 'youtube.com/[ev]/([^/]+)' + id or= link\match 'youtube.com/embed/([^/]+)' + + assert id, "couldn't parse youtube URL: '#{link}'" + + iframe { + width: 560 + height: 315 + frameborder: 0 + allowfullscreen: true + frameBorder: 0 + src: "//www.youtube.com/embed/#{id}" + } + }, + { + inp: 'URL -> image/.+', + out: 'mmm/dom', + transform: (src, fileder) -> img :src + }, + { + inp: 'URL -> video/.+', + out: 'mmm/dom', + transform: (src) -> + -- @TODO: add parsed MIME type + video (source :src), controls: true, loop: true + }, + { + inp: 'text/plain', + out: 'mmm/dom', + transform: (val) -> span val + }, + { + inp: 'alpha', + out: 'mmm/dom', + transform: single code + }, + { + inp: 'URL -> .*', + out: 'mmm/dom', + transform: single code + }, +} + +if MODE == 'SERVER' + ok, moon = pcall require, 'moonscript.base' + if ok + _load = moon.load or moon.loadstring + table.insert converts, { + inp: 'text/moonscript -> (.+)', + out: '%1', + transform: loadwith moon.load or moon.loadstring + } + + table.insert converts, { + inp: 'text/moonscript -> (.+)', + out: 'text/lua -> %1', + transform: single moon.to_lua + } +else + table.insert converts, { + inp: 'text/javascript -> (.+)', + out: '%1', + transform: (source) -> + f = js.new window.Function, source + f! + } + +do + local markdown + if MODE == 'SERVER' + success, discount = pcall require, 'discount' + if not success + warn "NO MARKDOWN SUPPORT!", discount + + markdown = success and (md) -> + res = assert discount.compile md, 'githubtags' + res.body + else + markdown = window and window.marked and window\marked + + if markdown + table.insert converts, { + inp: 'text/markdown', + out: 'text/html+frag', + transform: (md) -> "
#{markdown md}
" + } + + table.insert converts, { + inp: 'text/markdown%+span', + out: 'mmm/dom', + transform: if MODE == 'SERVER' + (source) -> + html = markdown source + html = html\gsub '^$', '/span>' + else + (source) -> + html = markdown source + html = html\gsub '^%s*

%s*', '' + html = html\gsub '%s*

%s*$', '' + with document\createElement 'span' + .innerHTML = html + } + +converts diff --git a/mmm/mmmfs/layout.moon b/mmm/mmmfs/layout.moon new file mode 100644 index 0000000..47e511b --- /dev/null +++ b/mmm/mmmfs/layout.moon @@ -0,0 +1,166 @@ +require = relative ..., 1 +import header, aside, footer, div, svg, script, g, circle, h1, span, b, a, img from require 'mmm.dom' +import navigate_to from (require 'mmm.mmmfs.util') require 'mmm.dom' + +pick = (...) -> + num = select '#', ... + i = math.ceil math.random! * num + select i, ... + +iconlink = (href, src, alt, style) -> a { + class: 'iconlink', + target: '_blank', + rel: 'me', + :href, + img :src, :alt, :style +} + +logo = svg { + class: 'sun' + viewBox: '-0.75 -1 1.5 2' + xmlns: 'http://www.w3.org/2000/svg' + baseProfile: 'full' + version: '1.1' + + g { + transform: 'translate(0 .18)' + + g { class: 'circle out', circle r: '.6', fill: 'none', 'stroke-width': '.12' } + g { class: 'circle in', circle r: '.2', stroke: 'none' } + } +} + +header = header { + div { + h1 { + logo + span { + span 'mmm', class: 'bold' + '​' + '.s‑ol.nu' + } + } + span "fun stuff with code and wires" + -- pick 'fun', 'cool', 'weird', 'interesting', 'new' + -- pick 'stuff', 'things', 'projects', 'experiments', 'news' + -- "with" + -- pick 'mostly code', 'code and wires', 'silicon', 'electronics' + } + aside { + navigate_to '/about', 'about me' + navigate_to '/games', 'games' + navigate_to '/projects', 'other' + a { + href: 'mailto:s%20[removethis]%20[at]%20s-ol.nu' + 'contact' + script " + var l = document.currentScript.parentElement; + l.href = l.href.replace('%20[at]%20', '@'); + l.href = l.href.replace('%20[removethis]', '') + '?subject=Hey there :)'; + " + } + } +} + +footer = footer { + span { + 'made with \xe2\x98\xbd by ' + a 's-ol', href: 'https://twitter.com/S0lll0s' + ", #{os.date '%Y'}" + } + div { + class: 'icons', + iconlink 'https://github.com/s-ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/github.svg', 'github' + iconlink 'https://merveilles.town/@s_ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/mastodon.svg', 'mastodon' + iconlink 'https://twitter.com/S0lll0s', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/twitter.svg', 'twitter' + iconlink 'https://webring.xxiivv.com/#random', 'https://webring.xxiivv.com/icon.black.svg', 'webring', + { height: '1.3em', 'margin-left': '.3em', 'margin-top': '-0.12em' } + } +} + +get_meta = => + title = (@get 'title: text/plain') or @gett 'name: alpha' + + l = (str) -> + str = str\gsub '[%s\\n]+$', '' + str\gsub '\\n', ' ' + e = (str) -> string.format '%q', l str + + meta = " + + #{l title} + " + + if page_meta = @get '_meta: mmm/dom' + meta ..= page_meta + else + meta ..= " + + + + + + " + + if desc = @get 'description: text/plain' + meta ..= " + " + + meta + +render = (content, fileder) -> + buf = [[ + + + + + + + + ]] + buf ..= " + #{get_meta fileder} + + + #{header} + + #{content} + + #{footer} + " + buf ..= [[ + + + + + + + + ]] + buf ..= " + + + + " + + buf + +{ + :render +} -- cgit v1.2.3 From 186c5d9cdd690bb86496c7cb40dc6e2d5fedda7f Mon Sep 17 00:00:00 2001 From: s-ol Date: Mon, 7 Oct 2019 19:52:48 +0200 Subject: add ba_log entry 2019-10-07 --- .../mmmfs/ba_log/2019-10-07/text$markdown.md | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 root/articles/mmmfs/ba_log/2019-10-07/text$markdown.md diff --git a/root/articles/mmmfs/ba_log/2019-10-07/text$markdown.md b/root/articles/mmmfs/ba_log/2019-10-07/text$markdown.md new file mode 100644 index 0000000..46c6892 --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-10-07/text$markdown.md @@ -0,0 +1,40 @@ +Today I started working on the HTTP server that finds, converts and serves content stored in the (SQL) backend just-in-time (later the server could also cache content). + +The server can handle these types of requests: + +## Fileder Index Requests +A request like `GET /path/to/fileder/` (note the trailing slash) is used to query the contents of a fileder. +It solicits a JSON-encoded response that contains the full paths to all children of this fileder, as well as all facets currently stored, e.g: + + { + "children": [ + "/projects/vcv_mods", + "/projects/HowDoIOS", + "/projects/iii-telefoni", + "/projects/btrktrl", + "/projects/demoloops", + "/projects/VJmidiKit", + "/projects/gayngine", + "/projects/themer", + "/projects/chimpanzee_bukkaque" + ], + "facets": [ + ["", "text/moonscript -> fn -> mmm/dom"], + ["name", "alpha"], + ["title", "text/plain"] + ] + } + +## Facet Requests +A request like `GET /path/to/fileder/facet_name` is used to query a facet. +To differentiate a request for the 'unnamed' facet from an index request, unnamed facets are represented as a `:` character instead. +The type to ask for can be specified in a `MMM-Accept` header separately, it defaults to `text/html`. + +The server either sends back the (possibly converted) facet with a `200 OK` status, +or a `406 Not Acceptable` error if no conversion was possible. + +I also restructured the code a bit and moved some of the HTML-rendering code into the main mmmfs code. +Then I renamed the `text/html` type to `text/html+frag`, since it refers to only a fragment of HTML code, not a whole document, +and added a new *convert* from `text/html+frag` to `text/html` that wraps the fragment in the HTML template and style. + +the full code change is in commits [81e143f](https://git.s-ol.nu/mmm/commit/81e143fa8181a6adb58d7fba632bd31a13164410/) and [ad26c7c](https://git.s-ol.nu/mmm/commit/ad26c7c4e374f66a978f9946bbb083377f2224a6/) -- cgit v1.2.3 From 198194ea194b6f091868e71f7b129e36caa4d6f4 Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 8 Oct 2019 13:21:30 +0200 Subject: layout fixes: - link from logo to root - links to path/: unless `STATIC` is set --- mmm/mmmfs/converts.moon | 4 +- mmm/mmmfs/layout.moon | 124 ++++++++++++++++++++------------------ mmm/mmmfs/util.moon | 10 +++- scss/_browser.scss | 156 ++++++++++++++++++++++++------------------------ 4 files changed, 156 insertions(+), 138 deletions(-) diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon index f8aad9f..f508d23 100644 --- a/mmm/mmmfs/converts.moon +++ b/mmm/mmmfs/converts.moon @@ -42,7 +42,9 @@ converts = { { inp: 'text/html%+frag', out: 'text/html', - transform: (html, fileder) -> render html, fileder + transform: (html, fileder) -> + html = '
' .. html .. '
' + render html, fileder }, { inp: 'text/html%+frag', diff --git a/mmm/mmmfs/layout.moon b/mmm/mmmfs/layout.moon index 47e511b..6eead6d 100644 --- a/mmm/mmmfs/layout.moon +++ b/mmm/mmmfs/layout.moon @@ -5,7 +5,7 @@ import navigate_to from (require 'mmm.mmmfs.util') require 'mmm.dom' pick = (...) -> num = select '#', ... i = math.ceil math.random! * num - select i, ... + (select i, ...) iconlink = (href, src, alt, style) -> a { class: 'iconlink', @@ -30,37 +30,41 @@ logo = svg { } } -header = header { - div { - h1 { - logo - span { - span 'mmm', class: 'bold' - '​' - '.s‑ol.nu' +gen_header = -> + header { + div { + h1 { + navigate_to '', logo + span { + span 'mmm', class: 'bold' + '​' + '.s‑ol.nu' + } } + -- span "fun stuff with code and wires" + table.concat { + pick 'fun', 'cool', 'weird', 'interesting', 'new', 'pleasant' + pick 'stuff', 'things', 'projects', 'experiments', 'visuals', 'ideas' + pick "with", 'and' + pick 'mostly code', 'code and wires', 'silicon', 'electronics', 'shaders', + 'oscilloscopes', 'interfaces', 'hardware', 'FPGAs' + }, ' ' } - span "fun stuff with code and wires" - -- pick 'fun', 'cool', 'weird', 'interesting', 'new' - -- pick 'stuff', 'things', 'projects', 'experiments', 'news' - -- "with" - -- pick 'mostly code', 'code and wires', 'silicon', 'electronics' - } - aside { - navigate_to '/about', 'about me' - navigate_to '/games', 'games' - navigate_to '/projects', 'other' - a { - href: 'mailto:s%20[removethis]%20[at]%20s-ol.nu' - 'contact' - script " - var l = document.currentScript.parentElement; - l.href = l.href.replace('%20[at]%20', '@'); - l.href = l.href.replace('%20[removethis]', '') + '?subject=Hey there :)'; - " + aside { + navigate_to '/about', 'about me' + navigate_to '/games', 'games' + navigate_to '/projects', 'other' + a { + href: 'mailto:s%20[removethis]%20[at]%20s-ol.nu' + 'contact' + script " + var l = document.currentScript.parentElement; + l.href = l.href.replace('%20[at]%20', '@'); + l.href = l.href.replace('%20[removethis]', '') + '?subject=Hey there :)'; + " + } } } -} footer = footer { span { @@ -108,53 +112,59 @@ get_meta = => meta -render = (content, fileder) -> +render = (content, fileder, opts={}) -> + opts.meta or= get_meta fileder + opts.scripts or= '' + + unless opts.noview + content = [[ +
+
+ ]] .. content .. [[ +
+
+ ]] + buf = [[ - - - - + + ]] buf ..= " #{get_meta fileder} - #{header} + #{gen_header!} #{content} #{footer} " buf ..= [[ - - - - - - + + + + + + ]] + + buf ..= opts.scripts + -- buf ..= " - " diff --git a/mmm/mmmfs/util.moon b/mmm/mmmfs/util.moon index 5c25ed3..db0c432 100644 --- a/mmm/mmmfs/util.moon +++ b/mmm/mmmfs/util.moon @@ -3,6 +3,12 @@ merge = (orig={}, extra) -> for k,v in pairs extra attr[k] = v +tourl = (path) -> + if STATIC + path + else + "#{path}/:" + (elements) -> import a, div, pre from elements @@ -14,7 +20,7 @@ merge = (orig={}, extra) -> assert fileder, "no fileder passed." navigate_to = (path, name, opts={}) -> - opts.href = path + opts.href = tourl path opts.onclick = if MODE == 'CLIENT' then (e) => e\preventDefault! BROWSER\navigate path @@ -30,7 +36,7 @@ merge = (orig={}, extra) -> a name, merge attr, :href, target: '_blank' else a name, merge attr, { - href: fileder.path + href: tourl fileder.path onclick: if MODE == 'CLIENT' then (e) => e\preventDefault! BROWSER\navigate fileder.path diff --git a/scss/_browser.scss b/scss/_browser.scss index 4d4a260..2bfc73e 100644 --- a/scss/_browser.scss +++ b/scss/_browser.scss @@ -3,109 +3,109 @@ flex: 1; border-top: 0.2rem solid $gray-bright; +} - .view { - display: flex; - flex-direction: column; - - flex: 1 1 0; - min-width: 0; +.view { + display: flex; + flex-direction: column; - &.inspector { - top: 0; - position: sticky; - max-height: 100vh; - color: #c5c8c6; + flex: 1 1 0; + min-width: 0; - @include left-border; - border-color: $gray-dark; - background: $gray-dark; + &.inspector { + top: 0; + position: sticky; + max-height: 100vh; + color: #c5c8c6; - nav { - background: inherit; - } - - .content { - margin: 0; - padding: 0; - display: flex; - background: $gray-darker; - - > * { - display: block; - margin: 0; - padding: 1em; - border-radius: 0; - border: 0; - flex: 1; - } - } - } + @include left-border; + border-color: $gray-dark; + background: $gray-dark; nav { - position: sticky; - top: 0; + background: inherit; + } + .content { + margin: 0; + padding: 0; display: flex; - flex: 0 0 auto; - flex-wrap: wrap; - justify-content: space-between; - background: $gray-bright; - z-index: 1000; - - > span:first-of-type { - flex: 1 0 auto; - } + background: $gray-darker; > * { - margin: 1em; - white-space: nowrap; - } - - > .inspect-btn { - @include media-small() { display: none; } + display: block; + margin: 0; + padding: 1em; + border-radius: 0; + border: 0; + flex: 1; } } + } + + nav { + position: sticky; + top: 0; - .error-wrap { - flex: 0 0 auto; - padding: 1em 2em; - overflow: hidden; + display: flex; + flex: 0 0 auto; + flex-wrap: wrap; + justify-content: space-between; + background: $gray-bright; + z-index: 1000; + + > span:first-of-type { + flex: 1 0 auto; + } - background: $gray-fail; + > * { + margin: 1em; + white-space: nowrap; + } - &.empty { - display: none; - } + > .inspect-btn { + @include media-small() { display: none; } + } + } - > span { - display: inline-block; - margin-bottom: 0.5em; + .error-wrap { + flex: 0 0 auto; + padding: 1em 2em; + overflow: hidden; - font-weight: bold; - color: #f00; - } + background: $gray-fail; - > pre { - margin: 0; - } + &.empty { + display: none; } - .content { - flex: 1 1 auto; - overflow: auto; - padding: 1em 2em; + > span { + display: inline-block; + margin-bottom: 0.5em; + + font-weight: bold; + color: #f00; + } - position: relative; + > pre { + margin: 0; } } .content { - opacity: 1; - transition: opacity 150ms; + flex: 1 1 auto; + overflow: auto; + padding: 1em 2em; - body.loading & { - opacity: 0; - } + position: relative; + } +} + +.content { + opacity: 1; + transition: opacity 150ms; + + body.loading & { + opacity: 0; } } -- cgit v1.2.3 From d63e8f54a87076cfbd3cb458c3e2128f46a9038d Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 8 Oct 2019 13:24:24 +0200 Subject: serve static assets from as ?... --- .gitignore | 4 ++-- Tupfile | 16 ++++++++------- build/import.moon | 3 +-- build/render_all.moon | 3 ++- build/server.moon | 55 +++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 67 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 352e83e..d8591a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ -dist -out db.sqlite3 ##### TUP GITIGNORE ##### ##### Lines below automatically generated by Tup. ##### Do not edit. .tup /.gitignore +/out +/static diff --git a/Tupfile b/Tupfile index edb8b62..4c8ab29 100644 --- a/Tupfile +++ b/Tupfile @@ -3,13 +3,15 @@ include_rules !download = |> ^ DOWNLOAD %O^ curl -L https://github.com/fengari-lua/fengari-web/releases/download/@(FENGARI_VERSION)/`basename %o` > %o |> !sassc = |> ^ SCSS %b^ sassc @(SASS_ARGS) %f %o |> | %o.map -# download fengari dependencies -: |> !download |> out/fengari-web.js -: |> !download |> out/fengari-web.js.map -: static/* |> cp %f out/ |> out/%b - # render stylesheet -: scss/main.scss |> !sassc |> out/main.css +: scss/main.scss |> !sassc |> static/main.css + +# download fengari dependencies +: |> !download |> static/fengari-web.js +: |> !download |> static/fengari-web.js.map # bundle for client loading -: mmm/.bundle.lua | |> ^ WRAP %d^ moon &(build)/bundle_module.moon %o --wrap %f |> out/mmm.bundle.lua +: mmm/.bundle.lua | |> ^ WRAP %d^ moon &(build)/bundle_module.moon %o --wrap %f |> static/mmm.bundle.lua + +# copy for static builds +: foreach static/* |> cp %f out/ |> out/%b diff --git a/build/import.moon b/build/import.moon index b5def43..e87f12d 100644 --- a/build/import.moon +++ b/build/import.moon @@ -39,8 +39,7 @@ with SQLStore name: output, verbose: true continue if file == '$order' filepath = "#{dirpath}/#{file}" - attr = lfs.attributes filepath - switch attr.mode + switch lfs.attributes filepath, 'mode' when 'file' key, value = load_facet file, filepath \create_facet fileder, key.name, key.type, value diff --git a/build/render_all.moon b/build/render_all.moon index 4fe827b..7797b7b 100644 --- a/build/render_all.moon +++ b/build/render_all.moon @@ -18,7 +18,8 @@ import load_tree from require 'build.util' -- moon render_all.moon [db.sqlite3] [startpath] { file, startpath } = arg -export BROWSER +export BROWSER, STATIC +STATIC = true tree = load_tree SQLStore :name tree = tree\walk startpath if startpath diff --git a/build/server.moon b/build/server.moon index b178636..a78f922 100644 --- a/build/server.moon +++ b/build/server.moon @@ -8,10 +8,12 @@ add '?/init' add '?/init.server' require 'mmm' + import dir_base, load_tree from require 'build.util' import Key from require 'mmm.mmmfs.fileder' import SQLStore from require 'mmm.mmmfs.drivers.sql' +lfs = require 'lfs' server = require 'http.server' headers = require 'http.headers' @@ -66,8 +68,6 @@ class Server -- no facet given facets = [{k.name, k.type} for k,v in pairs fileder.facets] children = [f.path for f in *fileder.children] - print facets - print children contents = tojson :facets, :children 200, contents else @@ -81,6 +81,57 @@ class Server method = req\get ':method' path = req\get ':path' + if path\match '^/%?' + -- serve static assets, cheap hack for now + + res = headers.new! + if method ~= 'GET' and method ~= 'HEAD' + res\append ':status', '405' + stream\write_headers res, true + return + + static_path = "static/#{path\sub 3}" + + if 'file' == lfs.attributes static_path, 'mode' + fd, err, errno = io.open static_path, 'rb' + + if not fd + code = switch errno + when ce.ENOENT then '404' + when ce.EACCES then '403' + else '503' + + res\upsert ':status', code + res\append 'content-type', 'text/plain' + + assert stream\write_headers res, method == 'HEAD' + if method ~= 'HEAD' + assert stream\write_body_from_string err + + else + suffix = static_path\match '%.([a-z]+)$' + type = switch suffix + when 'css' then 'text/css' + when 'lua' then 'application/lua' + when 'js' then 'application/javascript' + else 'application/octet-stream' + + res\upsert ':status', '200' + res\append 'content-type', type + + assert stream\write_headers res, method == 'HEAD' + if method ~= 'HEAD' + assert stream\write_body_from_file fd + else + res\upsert ':status', '404' + res\append 'content-type', 'text/plain' + + assert stream\write_headers res, method == 'HEAD' + if method ~= 'HEAD' + assert stream\write_body_from_string "not found" + + return + path, facet = dir_base path facet = if #facet > 0 facet = '' if facet == ':' -- cgit v1.2.3 From 906f68559479253f7035f42c953bf81dec5331b6 Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 8 Oct 2019 14:35:41 +0200 Subject: change server path mapping --- build/server.moon | 114 +++++++++++++++++++++++++------------------------- mmm/mmmfs/layout.moon | 8 ++-- mmm/mmmfs/util.moon | 4 +- 3 files changed, 64 insertions(+), 62 deletions(-) diff --git a/build/server.moon b/build/server.moon index a78f922..4749736 100644 --- a/build/server.moon +++ b/build/server.moon @@ -63,7 +63,7 @@ class Server if val 200, val else - 406, 'cant convert facet' + 406, "cant convert facet '#{facet.name}' to '#{facet.type}'" elseif fileder -- no facet given facets = [{k.name, k.type} for k,v in pairs fileder.facets] @@ -74,71 +74,75 @@ class Server -- fileder not found 404, "fileder '#{path}' not found" else - 501, 'not implemented' + 501, "not implemented" - stream: (sv, stream) => - req = stream\get_headers! - method = req\get ':method' - path = req\get ':path' - - if path\match '^/%?' - -- serve static assets, cheap hack for now + handle_static: (method, path, stream) => + path = path\match '^/%?static/(.*)' + return unless path + respond = (code, type, body) -> res = headers.new! - if method ~= 'GET' and method ~= 'HEAD' - res\append ':status', '405' - stream\write_headers res, true - return + res\upsert ':status', code + res\append 'content-type', type - static_path = "static/#{path\sub 3}" + assert stream\write_headers res, method == 'HEAD' + if body and method ~= 'HEAD' + assert stream\write_body_from_string body - if 'file' == lfs.attributes static_path, 'mode' - fd, err, errno = io.open static_path, 'rb' + if method ~= 'GET' and method ~= 'HEAD' + respond '405', 'text/plain', "can only GET/HEAD static resources" + return true - if not fd - code = switch errno - when ce.ENOENT then '404' - when ce.EACCES then '403' - else '503' + if path\match '^%.' or path\match '^%~' + respond '404', 'text/plain', "not found" + return - res\upsert ':status', code - res\append 'content-type', 'text/plain' + file_path = "static/#{path}" + if 'file' == lfs.attributes file_path, 'mode' + fd, err, errno = io.open file_path, 'rb' - assert stream\write_headers res, method == 'HEAD' - if method ~= 'HEAD' - assert stream\write_body_from_string err + if not fd + code = switch errno + when ce.ENOENT then '404' + when ce.EACCES then '403' + else '503' - else - suffix = static_path\match '%.([a-z]+)$' - type = switch suffix - when 'css' then 'text/css' - when 'lua' then 'application/lua' - when 'js' then 'application/javascript' - else 'application/octet-stream' - - res\upsert ':status', '200' - res\append 'content-type', type - - assert stream\write_headers res, method == 'HEAD' - if method ~= 'HEAD' - assert stream\write_body_from_file fd - else - res\upsert ':status', '404' - res\append 'content-type', 'text/plain' + respond code, 'text/plain', err or '' - assert stream\write_headers res, method == 'HEAD' + else + suffix = file_path\match '%.([a-z]+)$' + type = switch suffix + when 'css' then 'text/css' + when 'lua' then 'application/lua' + when 'js' then 'application/javascript' + else 'application/octet-stream' + + respond '200', type, nil if method ~= 'HEAD' - assert stream\write_body_from_string "not found" + assert stream\write_body_from_file fd + else + respond '404', 'text/plain', "not found" - return + true - path, facet = dir_base path - facet = if #facet > 0 - facet = '' if facet == ':' - accept = req\get 'mmm-accept' - Key facet, accept or 'text/html' + stream: (sv, stream) => + req = stream\get_headers! + method = req\get ':method' + path = req\get ':path' + + -- serve static assets, cheap hack for now + return if @handle_static method, path, stream + + path_facet, type = path\match '(.*):(.*)' + path_facet or= path + path, facet = path_facet\match '(.*)/([^/]*)' + + if facet ~= '?index' + type or= 'text/html' + type = type\match '%s*(.*)' + facet = Key facet, type else - nil + facet = nil status, body = @handle method, path, facet @@ -149,10 +153,8 @@ class Server res\append ':status', tostring status res\append 'content-type', response_type - if method == 'HEAD' - stream\write_headers res, true - else - stream\write_headers res, false + stream\write_headers res, method == 'HEAD' + if method ~= 'HEAD' stream\write_chunk body, true error: (sv, ctx, op, err, errno) => diff --git a/mmm/mmmfs/layout.moon b/mmm/mmmfs/layout.moon index 6eead6d..7312cb5 100644 --- a/mmm/mmmfs/layout.moon +++ b/mmm/mmmfs/layout.moon @@ -129,7 +129,7 @@ render = (content, fileder, opts={}) -> - + ]] buf ..= " @@ -143,12 +143,12 @@ render = (content, fileder, opts={}) -> #{footer} " buf ..= [[ - + - - + + ]] diff --git a/mmm/mmmfs/util.moon b/mmm/mmmfs/util.moon index db0c432..9e0a0b0 100644 --- a/mmm/mmmfs/util.moon +++ b/mmm/mmmfs/util.moon @@ -5,9 +5,9 @@ merge = (orig={}, extra) -> tourl = (path) -> if STATIC - path + path .. '/' else - "#{path}/:" + path .. '/' (elements) -> import a, div, pre from elements -- cgit v1.2.3 From 20aeafec7fee769fe8889b3a1ae8e0557273d628 Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 8 Oct 2019 14:36:07 +0200 Subject: fix conversion pattern escapes --- mmm/mmmfs/conversion.moon | 7 ++++--- mmm/mmmfs/converts.moon | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/mmm/mmmfs/conversion.moon b/mmm/mmmfs/conversion.moon index 54cd680..871ba7e 100644 --- a/mmm/mmmfs/conversion.moon +++ b/mmm/mmmfs/conversion.moon @@ -2,14 +2,15 @@ require = relative ..., 1 converts = require '.converts' count = (base, pattern='->') -> select 2, base\gsub pattern, '' -escape_pattern = (inp) -> "^#{inp\gsub '([-/])', '%%%1'}$" +escape_pattern = (inp) -> "^#{inp\gsub '([^%w])', '%%%1'}$" +escape_inp = (inp) -> "^#{inp\gsub '([-/])', '%%%1'}$" -- attempt to find a conversion path from 'have' to 'want' -- * have - start type string or list of type strings -- * want - stop type pattern -- * limit - limit conversion amount -- returns a list of conversion steps -get_conversions = (want, have, _converts=converts, limit=3) -> +get_conversions = (want, have, _converts=converts, limit=5) -> assert have, 'need starting type(s)' if 'string' == type have @@ -28,7 +29,7 @@ get_conversions = (want, have, _converts=converts, limit=3) -> return conversions, start else for convert in *_converts - inp = escape_pattern convert.inp + inp = escape_inp convert.inp continue unless rest\match inp result = rest\gsub inp, convert.out if result diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon index f508d23..766c8ad 100644 --- a/mmm/mmmfs/converts.moon +++ b/mmm/mmmfs/converts.moon @@ -201,7 +201,7 @@ converts = { transform: single code }, { - inp: 'URL -> .*', + inp: 'URL -> .+', out: 'mmm/dom', transform: single code }, -- cgit v1.2.3 From 7f261ca5fe336d3d3a0ab9147fd7a5feecdaf36c Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 8 Oct 2019 14:46:16 +0200 Subject: change static path to work with static content --- .gitignore | 1 - Tupfile | 2 +- build/server.moon | 4 ++-- mmm/Tupdefault | 1 - mmm/mmmfs/layout.moon | 8 ++++---- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index d8591a3..031652c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,3 @@ db.sqlite3 .tup /.gitignore /out -/static diff --git a/Tupfile b/Tupfile index 4c8ab29..29388cf 100644 --- a/Tupfile +++ b/Tupfile @@ -14,4 +14,4 @@ include_rules : mmm/.bundle.lua | |> ^ WRAP %d^ moon &(build)/bundle_module.moon %o --wrap %f |> static/mmm.bundle.lua # copy for static builds -: foreach static/* |> cp %f out/ |> out/%b +: foreach static/* |> cp %f out/.static/ |> out/.static/%b diff --git a/build/server.moon b/build/server.moon index 4749736..a9b8431 100644 --- a/build/server.moon +++ b/build/server.moon @@ -77,7 +77,7 @@ class Server 501, "not implemented" handle_static: (method, path, stream) => - path = path\match '^/%?static/(.*)' + path = path\match '^/%.static/(.*)' return unless path respond = (code, type, body) -> @@ -93,7 +93,7 @@ class Server respond '405', 'text/plain', "can only GET/HEAD static resources" return true - if path\match '^%.' or path\match '^%~' + if path\match '%.%.' or path\match '^%~' respond '404', 'text/plain', "not found" return diff --git a/mmm/Tupdefault b/mmm/Tupdefault index 3a0783f..8035ed5 100644 --- a/mmm/Tupdefault +++ b/mmm/Tupdefault @@ -1,5 +1,4 @@ include_rules - : foreach *.moon |> ^ MOON %f^ moonc -p > %o %f |> %B.lua : |> ^ BNDL %d^ moon &(build)/bundle_module.moon %o %d % |> .bundle.lua ../ diff --git a/mmm/mmmfs/layout.moon b/mmm/mmmfs/layout.moon index 7312cb5..0fbf553 100644 --- a/mmm/mmmfs/layout.moon +++ b/mmm/mmmfs/layout.moon @@ -129,7 +129,7 @@ render = (content, fileder, opts={}) -> - + ]] buf ..= " @@ -143,12 +143,12 @@ render = (content, fileder, opts={}) -> #{footer} " buf ..= [[ - + - - + + ]] -- cgit v1.2.3 From 92861ee9812b30b68f87f5c0f13125119e592473 Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 8 Oct 2019 15:37:53 +0200 Subject: add anything -> URL cast --- build/import.moon | 2 +- mmm/mmmfs/browser.moon | 4 ++-- mmm/mmmfs/conversion.moon | 6 +++--- mmm/mmmfs/converts.moon | 48 ++++++++++++++++++++++++++--------------------- 4 files changed, 33 insertions(+), 27 deletions(-) diff --git a/build/import.moon b/build/import.moon index e87f12d..aa8250e 100644 --- a/build/import.moon +++ b/build/import.moon @@ -24,7 +24,7 @@ load_facet = (filename, filepath) -> key = Key key\gsub '%$', '/' key.filename = filename - file = assert (io.open filepath, 'r'), "couldn't open facet file '#{filename}'" + file = assert (io.open filepath, 'rb'), "couldn't open facet file '#{filename}'" value = file\read '*all' file\close! diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index 944cc72..37a386c 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -2,7 +2,7 @@ require = relative ..., 1 import Key from require '.fileder' import converts, get_conversions, apply_conversions from require '.conversion' import ReactiveVar, get_or_create, text, elements from require 'mmm.component' -import pre, div, nav, span, button, a, select, option from elements +import pre, div, nav, span, button, a, code, select, option from elements import languages from require 'mmm.highlighting' keep = (var) -> @@ -32,7 +32,7 @@ casts = { { inp: 'URL.*' out: 'mmm/dom' - transform: (href) -> span a href, :href + transform: (href) -> span a (code href), :href }, } diff --git a/mmm/mmmfs/conversion.moon b/mmm/mmmfs/conversion.moon index 871ba7e..2c68dcc 100644 --- a/mmm/mmmfs/conversion.moon +++ b/mmm/mmmfs/conversion.moon @@ -36,7 +36,7 @@ get_conversions = (want, have, _converts=converts, limit=5) -> next_have[c] = { :start, rest: result, - conversions: { convert, table.unpack conversions } + conversions: { { :convert, from: rest, to: result }, table.unpack conversions } } c += 1 @@ -50,8 +50,8 @@ get_conversions = (want, have, _converts=converts, limit=5) -> -- returns converted value apply_conversions = (conversions, value, ...) -> for i=#conversions,1,-1 - { :inp, :out, :transform } = conversions[i] - value = transform value, ... + step = conversions[i] + value = step.convert.transform step, value, ... value diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon index 766c8ad..020f765 100644 --- a/mmm/mmmfs/converts.moon +++ b/mmm/mmmfs/converts.moon @@ -11,10 +11,10 @@ js_fix = if MODE == 'CLIENT' arg -- limit function to one argument -single = (func) -> (val) -> func val +single = (func) -> (val) => func val -- load a chunk using a specific 'load'er -loadwith = (_load) -> (val, fileder, key) -> +loadwith = (_load) -> (val, fileder, key) => func = assert _load val, "#{fileder}##{key}" func! @@ -27,7 +27,7 @@ converts = { { inp: 'fn -> (.+)', out: '%1', - transform: (val, fileder) -> val fileder + transform: (val, fileder) => val fileder }, { inp: 'mmm/component', @@ -37,12 +37,12 @@ converts = { { inp: 'mmm/dom', out: 'text/html+frag', - transform: (node) -> if MODE == 'SERVER' then node else node.outerHTML + transform: (node) => if MODE == 'SERVER' then node else node.outerHTML }, { inp: 'text/html%+frag', out: 'text/html', - transform: (html, fileder) -> + transform: (html, fileder) => html = '
' .. html .. '
' render html, fileder }, @@ -50,7 +50,7 @@ converts = { inp: 'text/html%+frag', out: 'mmm/dom', transform: if MODE == 'SERVER' - (html, fileder) -> + (html, fileder) => html = html\gsub '(.-)', (attrs, text) -> text = nil if #text == 0 path = '' @@ -93,7 +93,7 @@ converts = { html else - (html, fileder) -> + (html, fileder) => parent = with document\createElement 'div' .innerHTML = html @@ -128,7 +128,7 @@ converts = { { inp: 'mmm/tpl -> (.+)', out: '%1', - transform: (source, fileder) -> + transform: (source, fileder) => source\gsub '{{(.-)}}', (expr) -> path, facet = expr\match '^([%w%-_%./]*)%+(.*)' assert path, "couldn't match TPL expression '#{expr}'" @@ -138,7 +138,7 @@ converts = { { inp: 'time/iso8601-date', out: 'time/unix', - transform: (val) -> + transform: (val) => year, _, month, day = val\match '^%s*(%d%d%d%d)(%-?)([01]%d)%2([0-3]%d)%s*$' assert year, "failed to parse ISO 8601 date: '#{val}'" os.time :year, :month, :day @@ -146,7 +146,7 @@ converts = { { inp: 'URL -> twitter/tweet', out: 'mmm/dom', - transform: (href) -> + transform: (href) => id = assert (href\match 'twitter.com/[^/]-/status/(%d*)'), "couldn't parse twitter/tweet URL: '#{href}'" if MODE == 'CLIENT' with parent = div! @@ -161,7 +161,7 @@ converts = { { inp: 'URL -> youtube/video', out: 'mmm/dom', - transform: (link) -> + transform: (link) => id = link\match 'youtu%.be/([^/]+)' id or= link\match 'youtube.com/watch.*[?&]v=([^&]+)' id or= link\match 'youtube.com/[ev]/([^/]+)' @@ -181,29 +181,35 @@ converts = { { inp: 'URL -> image/.+', out: 'mmm/dom', - transform: (src, fileder) -> img :src + transform: (src, fileder) => img :src }, { inp: 'URL -> video/.+', out: 'mmm/dom', - transform: (src) -> + transform: (src) => -- @TODO: add parsed MIME type video (source :src), controls: true, loop: true }, { inp: 'text/plain', out: 'mmm/dom', - transform: (val) -> span val + transform: (val) => span val }, { inp: 'alpha', out: 'mmm/dom', transform: single code }, + -- this one needs a higher cost + -- { + -- inp: 'URL -> .+', + -- out: 'mmm/dom', + -- transform: single code + -- }, { - inp: 'URL -> .+', - out: 'mmm/dom', - transform: single code + inp: '(.+)', + out: 'URL -> %1', + transform: (_, fileder, key) => "#{fileder.path}/#{key.name}:#{@from}" }, } @@ -226,7 +232,7 @@ else table.insert converts, { inp: 'text/javascript -> (.+)', out: '%1', - transform: (source) -> + transform: (source) => f = js.new window.Function, source f! } @@ -248,19 +254,19 @@ do table.insert converts, { inp: 'text/markdown', out: 'text/html+frag', - transform: (md) -> "
#{markdown md}
" + transform: (md) => "
#{markdown md}
" } table.insert converts, { inp: 'text/markdown%+span', out: 'mmm/dom', transform: if MODE == 'SERVER' - (source) -> + (source) => html = markdown source html = html\gsub '^$', '/span>' else - (source) -> + (source) => html = markdown source html = html\gsub '^%s*

%s*', '' html = html\gsub '%s*

%s*$', '' -- cgit v1.2.3 From ca96a23197e3d1dcb11b68cc1d15aafa516d5ac9 Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 8 Oct 2019 19:04:21 +0200 Subject: realtime server Dockerfile --- Dockerfile | 27 +++++++++++++++++---------- build/import.moon | 4 ++-- build/render_all.moon | 2 +- build/server.moon | 6 +++--- mmm/mmmfs/drivers/sql.moon | 6 +++--- 5 files changed, 26 insertions(+), 19 deletions(-) diff --git a/Dockerfile b/Dockerfile index af0f4b5..f8c158b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,19 @@ -FROM nickblah/lua:5.3-luarocks-stretch AS build-env -RUN echo "deb http://ppa.launchpad.net/jonathonf/tup/ubuntu xenial main" >/etc/apt/sources.list.d/tup.list -RUN apt-get update -RUN apt-get install -y --allow-unauthenticated build-essential tup sassc libmarkdown2-dev -RUN luarocks install moonscript +FROM nickblah/lua:5.3-luarocks-stretch + +RUN echo "deb http://ppa.launchpad.net/jonathonf/tup/ubuntu xenial main" \ + >/etc/apt/sources.list.d/tup.list +RUN apt-get update && \ + apt-get install -y --allow-unauthenticated \ + build-essential m4 tup sassc \ + libmarkdown2-dev libsqlite3-dev libssl-dev RUN luarocks install discount DISCOUNT_INCDIR=/usr/include/x86_64-linux-gnu -COPY . /build -RUN cd /build && tup init && tup generate --config tup.docker.config build.sh && ./build.sh +RUN luarocks install moonscript +RUN luarocks install sqlite3 +RUN luarocks install http + +COPY . /code +WORKDIR /code +RUN tup init && tup generate --config tup.docker.config build-static.sh && ./build-static.sh -FROM nginx:alpine -COPY --from=build-env /build/root /usr/share/nginx/html -RUN chmod 555 -R /usr/share/nginx/html +EXPOSE 8000 +ENTRYPOINT ["moon", "build/server.moon", "/db.sqlite3", "0.0.0.0", "8000"] diff --git a/build/import.moon b/build/import.moon index aa8250e..ceb56ad 100644 --- a/build/import.moon +++ b/build/import.moon @@ -14,7 +14,7 @@ import SQLStore from require 'mmm.mmmfs.drivers.sql' -- usage: -- moon import.moon [output.sqlite3] -{ root, output } = arg +{ root, file } = arg assert root, "please specify the root directory" @@ -30,7 +30,7 @@ load_facet = (filename, filepath) -> key, value -with SQLStore name: output, verbose: true +with SQLStore :file, verbose: true import_fileder = (fileder, dirpath) -> for file in lfs.dir dirpath continue if '.' == file\sub 1, 1 diff --git a/build/render_all.moon b/build/render_all.moon index 7797b7b..259346b 100644 --- a/build/render_all.moon +++ b/build/render_all.moon @@ -21,7 +21,7 @@ import load_tree from require 'build.util' export BROWSER, STATIC STATIC = true -tree = load_tree SQLStore :name +tree = load_tree SQLStore :file tree = tree\walk startpath if startpath for fileder in coroutine.wrap tree\iterate diff --git a/build/server.moon b/build/server.moon index a9b8431..3731879 100644 --- a/build/server.moon +++ b/build/server.moon @@ -163,9 +163,9 @@ class Server print msg -- usage: --- moon server.moon [db.sqlite3] -{ file } = arg +-- moon server.moon [db.sqlite3] [host] [port] +{ file, host, port } = arg tree = load_tree SQLStore :file -server = Server tree +server = Server tree, :host, port: port and tonumber port server\listen! diff --git a/mmm/mmmfs/drivers/sql.moon b/mmm/mmmfs/drivers/sql.moon index 514985c..9337dd8 100644 --- a/mmm/mmmfs/drivers/sql.moon +++ b/mmm/mmmfs/drivers/sql.moon @@ -2,7 +2,7 @@ sqlite = require 'sqlite3' class SQLStore new: (opts = {}) => - opts.name or= 'db.sqlite3' + opts.file or= 'db.sqlite3' opts.verbose or= false opts.memory or= false @@ -13,8 +13,8 @@ class SQLStore @log "opening in-memory DB..." @db = sqlite.open_memory! else - @log "opening '#{opts.name}'..." - @db = sqlite.open opts.name + @log "opening '#{opts.file}'..." + @db = sqlite.open opts.file assert @db\exec [[ PRAGMA foreign_keys = ON; -- cgit v1.2.3 From 75b1f5a1a21069154d41742a84970f4d2ccb2d58 Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 8 Oct 2019 21:46:55 +0200 Subject: fix header, double div.content --- mmm/mmmfs/converts.moon | 4 +--- scss/_header.scss | 6 +++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon index 020f765..8d6b953 100644 --- a/mmm/mmmfs/converts.moon +++ b/mmm/mmmfs/converts.moon @@ -42,9 +42,7 @@ converts = { { inp: 'text/html%+frag', out: 'text/html', - transform: (html, fileder) => - html = '
' .. html .. '
' - render html, fileder + transform: (html, fileder) => render html, fileder }, { inp: 'text/html%+frag', diff --git a/scss/_header.scss b/scss/_header.scss index ccaf658..fd3aec3 100644 --- a/scss/_header.scss +++ b/scss/_header.scss @@ -26,8 +26,12 @@ header { font-weight: 400; } - .sun { + > a { height: 5rem; + } + + .sun { + height: 100%; stroke: currentColor; fill: currentColor; -- cgit v1.2.3 From 053624c2b71f894d71e9b782475679d1cef5a926 Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 8 Oct 2019 21:59:18 +0200 Subject: urlDecode incoming request paths --- build/server.moon | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/server.moon b/build/server.moon index 3731879..8fb0615 100644 --- a/build/server.moon +++ b/build/server.moon @@ -12,6 +12,7 @@ require 'mmm' import dir_base, load_tree from require 'build.util' import Key from require 'mmm.mmmfs.fileder' import SQLStore from require 'mmm.mmmfs.drivers.sql' +import decodeURI from require 'http.util' lfs = require 'lfs' server = require 'http.server' @@ -129,6 +130,7 @@ class Server req = stream\get_headers! method = req\get ':method' path = req\get ':path' + path = decodeURI path -- serve static assets, cheap hack for now return if @handle_static method, path, stream -- cgit v1.2.3 From 9af30efac1e975b18a43d82f575b91bd7bd2b426 Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 8 Oct 2019 22:17:33 +0200 Subject: add ba_log entry 2019-10-08 --- .../mmmfs/ba_log/2019-10-08/text$markdown.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 root/articles/mmmfs/ba_log/2019-10-08/text$markdown.md diff --git a/root/articles/mmmfs/ba_log/2019-10-08/text$markdown.md b/root/articles/mmmfs/ba_log/2019-10-08/text$markdown.md new file mode 100644 index 0000000..7d69a3a --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-10-08/text$markdown.md @@ -0,0 +1,22 @@ +Today I mostly fixed the output/rendering of the 'live' server I implemented yesterday. + +I changed the URL scheme, it no longer uses headers, which made it hard to link to resources through `` and ` + - - + + ]] diff --git a/root/static/fengari-web/application$javascript.js b/root/static/fengari-web/application$javascript.js new file mode 100644 index 0000000..5d2de8e --- /dev/null +++ b/root/static/fengari-web/application$javascript.js @@ -0,0 +1,8 @@ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.fengari=e():t.fengari=e()}(window,function(){return function(t){var e={};function r(n){if(e[n])return e[n].exports;var a=e[n]={i:n,l:!1,exports:{}};return t[n].call(a.exports,a,a.exports,r),a.l=!0,a.exports}return r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var a in t)r.d(n,a,function(e){return t[e]}.bind(null,a));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=34)}([function(t,e,r){"use strict"; +/** +@license MIT + +Copyright © 2017-2018 Benoit Giannangeli +Copyright © 2017-2018 Daurnimator +Copyright © 1994–2017 Lua.org, PUC-Rio. +*/var n=r(5);t.exports.FENGARI_AUTHORS=n.FENGARI_AUTHORS,t.exports.FENGARI_COPYRIGHT=n.FENGARI_COPYRIGHT,t.exports.FENGARI_RELEASE=n.FENGARI_RELEASE,t.exports.FENGARI_VERSION=n.FENGARI_VERSION,t.exports.FENGARI_VERSION_MAJOR=n.FENGARI_VERSION_MAJOR,t.exports.FENGARI_VERSION_MINOR=n.FENGARI_VERSION_MINOR,t.exports.FENGARI_VERSION_NUM=n.FENGARI_VERSION_NUM,t.exports.FENGARI_VERSION_RELEASE=n.FENGARI_VERSION_RELEASE,t.exports.luastring_eq=n.luastring_eq,t.exports.luastring_indexOf=n.luastring_indexOf,t.exports.luastring_of=n.luastring_of,t.exports.to_jsstring=n.to_jsstring,t.exports.to_luastring=n.to_luastring,t.exports.to_uristring=n.to_uristring;var a=r(3),u=r(2),s=r(7),o=r(17);t.exports.luaconf=a,t.exports.lua=u,t.exports.lauxlib=s,t.exports.lualib=o},function(t,e,r){"use strict";var n,a,u;if(n="function"==typeof Uint8Array.from?Uint8Array.from.bind(Uint8Array):function(t){for(var e=0,r=t.length,n=new Uint8Array(r);r>e;)n[e]=t[e++];return n},"function"==typeof(new Uint8Array).indexOf)a=function(t,e,r){return t.indexOf(e,r)};else{var s=[].indexOf;if(0!==s.call(new Uint8Array(1),0))throw Error("missing .indexOf");a=function(t,e,r){return s.call(t,e,r)}}u="function"==typeof Uint8Array.of?Uint8Array.of.bind(Uint8Array):function(){return n(arguments)};var o=function(t){return t instanceof Uint8Array},l="cannot convert invalid utf8 to javascript string",i=";,/?:@&=+$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,-_.!~*'()#".split("").reduce(function(t,e){return t[e.charCodeAt(0)]=!0,t},{}),c={},f=function(t,e){if("string"!=typeof t)throw new TypeError("to_luastring expects a javascript string");if(e){var r=c[t];if(o(r))return r}for(var a=t.length,u=Array(a),s=0,l=0;l>6,u[s++]=128|63&i;else{if(i>=55296&&i<=56319&&l+1=56320&&f<=57343&&(l++,i=1024*(i-55296)+f+9216)}i<=65535?(u[s++]=224|i>>12,u[s++]=128|i>>6&63,u[s++]=128|63&i):(u[s++]=240|i>>18,u[s++]=128|i>>12&63,u[s++]=128|i>>6&63,u[s++]=128|63&i)}}return u=n(u),e&&(c[t]=u),u};t.exports.luastring_from=n,t.exports.luastring_indexOf=a,t.exports.luastring_of=u,t.exports.is_luastring=o,t.exports.luastring_eq=function(t,e){if(t!==e){var r=t.length;if(r!==e.length)return!1;for(var n=0;n244){if(!n)throw RangeError(l);a+="�"}else if(s<=223){if(u>=r){if(!n)throw RangeError(l);a+="�";continue}var i=t[u++];if(128!=(192&i)){if(!n)throw RangeError(l);a+="�";continue}a+=String.fromCharCode(((31&s)<<6)+(63&i))}else if(s<=239){if(u+1>=r){if(!n)throw RangeError(l);a+="�";continue}var c=t[u++];if(128!=(192&c)){if(!n)throw RangeError(l);a+="�";continue}var f=t[u++];if(128!=(192&f)){if(!n)throw RangeError(l);a+="�";continue}var _=((15&s)<<12)+((63&c)<<6)+(63&f);if(_<=65535)a+=String.fromCharCode(_);else{var p=55296+((_-=65536)>>10),v=_%1024+56320;a+=String.fromCharCode(p,v)}}else{if(u+2>=r){if(!n)throw RangeError(l);a+="�";continue}var h=t[u++];if(128!=(192&h)){if(!n)throw RangeError(l);a+="�";continue}var L=t[u++];if(128!=(192&L)){if(!n)throw RangeError(l);a+="�";continue}var d=t[u++];if(128!=(192&d)){if(!n)throw RangeError(l);a+="�";continue}var A=((7&s)<<18)+((63&h)<<12)+((63&L)<<6)+(63&d),g=55296+((A-=65536)>>10),T=A%1024+56320;a+=String.fromCharCode(g,T)}}return a},t.exports.to_uristring=function(t){if(!o(t))throw new TypeError("to_uristring expects a Uint8Array");for(var e="",r=0;r>>20&2047;0===r&&(e.setFloat64(0,t*Math.pow(2,64)),r=(e.getUint32(0)>>>20&2047)-64);var n=r-1022;return[A(t,-n),n]},t.exports.ldexp=A,t.exports.lua_getlocaledecpoint=function(){return 46},t.exports.lua_integer2str=function(t){return String(t)},t.exports.lua_number2str=function(t){return String(Number(t.toPrecision(14)))},t.exports.lua_numbertointeger=function(t){return t>=-2147483648&&t<2147483648&&t},t.exports.luai_apicheck=function(t,e){if(!e)throw Error(e)}},function(t,e,r){"use strict";var n=r(3).luai_apicheck,a=function(t){if(!t)throw Error("assertion failed")};t.exports.lua_assert=a,t.exports.luai_apicheck=n||function(t,e){return a(e)};t.exports.api_check=function(t,e,r){return n(t,e&&r)};t.exports.LUAI_MAXCCALLS=200;t.exports.LUA_MINBUFFER=32;t.exports.luai_nummod=function(t,e,r){var n=e%r;return n*r<0&&(n+=r),n};t.exports.MAX_INT=2147483647;t.exports.MIN_INT=-2147483648},function(t,e,r){var n=r(1),a="Fengari 0.1.4 Copyright (C) 2017-2018 B. Giannangeli, Daurnimator\nBased on: "+n.LUA_COPYRIGHT;t.exports.FENGARI_AUTHORS="B. Giannangeli, Daurnimator",t.exports.FENGARI_COPYRIGHT=a,t.exports.FENGARI_RELEASE="Fengari 0.1.4",t.exports.FENGARI_VERSION="Fengari 0.1",t.exports.FENGARI_VERSION_MAJOR="0",t.exports.FENGARI_VERSION_MINOR="1",t.exports.FENGARI_VERSION_NUM=1,t.exports.FENGARI_VERSION_RELEASE="4",t.exports.is_luastring=n.is_luastring,t.exports.luastring_eq=n.luastring_eq,t.exports.luastring_from=n.luastring_from,t.exports.luastring_indexOf=n.luastring_indexOf,t.exports.luastring_of=n.luastring_of,t.exports.to_jsstring=n.to_jsstring,t.exports.to_luastring=n.to_luastring,t.exports.to_uristring=n.to_uristring,t.exports.from_userstring=n.from_userstring},function(t,e,r){"use strict";var n;function a(t){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function u(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function s(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){for(var r=0;r>=6,n>>=1}while(e>n);t[8-r]=~n<<1|e}return r},Nt=function(t,e){var r="x"===e?function(t){for(var e,r=0,n=0,a=0,u=0,s=0,o=!1;Z(t[r]);)r++;if((e=45===t[r])?r++:43===t[r]&&r++,48!==t[r]||120!==t[r+1]&&88!==t[r+1])return null;for(r+=2;;r++)if(46===t[r]){if(o)break;o=!0}else{if(!q(t[r]))break;0===a&&48===t[r]?u++:++a<=30?n=16*n+mt(t[r]):s++,o&&s--}if(u+a===0)return null;if(s*=4,112===t[r]||80===t[r]){var l,i=0;if((l=45===t[++r])?r++:43===t[r]&&r++,!Y(t[r]))return null;for(;Y(t[r]);)i=10*i+t[r++]-48;l&&(i=-i),s+=i}return e&&(n=-n),{n:st(n,s),i:r}}(t):function(t){try{t=H(t)}catch(t){return null}var e=/^[\t\v\f \n\r]*[+-]?(?:[0-9]+\.?[0-9]*|\.[0-9]*)(?:[eE][+-]?[0-9]+)?/.exec(t);if(!e)return null;var r=parseFloat(e[0]);return isNaN(r)?null:{n:r,i:e[0].length}}(t);if(null===r)return null;for(;Z(t[r.i]);)r.i++;return r.i===t.length||0===t[r.i]?r:null},Rt=[46,120,88,110,78],yt=(u(n={},46,"."),u(n,120,"x"),u(n,88,"x"),u(n,110,"n"),u(n,78,"n"),n),St=Math.floor(ft/10),wt=ft%10,It=function(t,e){var r;if(e.ttisinteger())r=X(ot(e.value));else{var n=lt(e.value);!ut&&/^[-0123456789]+$/.test(n)&&(n+=".0"),r=X(n)}e.setsvalue(et(t,r))},Mt=function(t,e){Q.luaD_inctop(t),At(t,t.top-1,rt(t,e))},Pt=function(t,e,r){for(var n,u=0,s=0,o=0;-1!=(n=F(e,37,s));){switch(Mt(t,e.subarray(s,n)),e[n+1]){case 115:var l=r[o++];if(null===l)l=X("(null)",!0);else{l=K(l);var i=F(l,0);-1!==i&&(l=l.subarray(0,i))}Mt(t,l);break;case 99:var c=r[o++];J(c)?Mt(t,j(c)):Ct(t,X("<\\%d>",!0),c);break;case 100:case 73:Q.luaD_inctop(t),t.stack[t.top-1].setivalue(r[o++]),It(t,t.stack[t.top-1]);break;case 102:Q.luaD_inctop(t),t.stack[t.top-1].setfltvalue(r[o++]),It(t,t.stack[t.top-1]);break;case 112:var f=r[o++];if(f instanceof $.lua_State||f instanceof nt.Table||f instanceof bt||f instanceof Tt||f instanceof xt)Mt(t,X("0x"+f.id.toString(16)));else switch(a(f)){case"undefined":Mt(t,X("undefined"));break;case"number":Mt(t,X("Number("+f+")"));break;case"string":Mt(t,X("String("+JSON.stringify(f)+")"));break;case"boolean":Mt(t,X(f?"Boolean(true)":"Boolean(false)"));break;case"object":if(null===f){Mt(t,X("null"));break}case"function":var _=t.l_G.ids.get(f);_||(_=t.l_G.id_counter++,t.l_G.ids.set(f,_)),Mt(t,X("0x"+_.toString(16)));break;default:Mt(t,X(""))}break;case 85:var p=new Uint8Array(8),v=Ut(p,r[o++]);Mt(t,p.subarray(8-v));break;case 37:Mt(t,X("%",!0));break;default:W.luaG_runerror(t,X("invalid option '%%%c' to 'lua_pushfstring'"),e[n+1])}u+=2,s=n+2}return Q.luaD_checkstack(t,1),Mt(t,e.subarray(s)),u>0&&it.luaV_concat(t,u+1),t.stack[t.top-1].svalue()},Ct=function(t,e){for(var r=arguments.length,n=new Array(r>2?r-2:0),a=2;ae&&(n=e),r.set(t.subarray(0,n),u),u+=n,r.set(kt,u),u+=kt.length),r.set(Et,u),u+=Et.length,r=r.subarray(0,u)}return r},t.exports.luaO_hexavalue=mt,t.exports.luaO_int2fb=function(t){var e=0;if(t<8)return t;for(;t>=128;)t=t+15>>4,e+=4;for(;t>=16;)t=t+1>>1,e++;return e+1<<3|t-8},t.exports.luaO_pushfstring=Ct,t.exports.luaO_pushvfstring=Pt,t.exports.luaO_str2num=function(t,e){var r=function(t){for(var e,r=0,n=0,a=!0;Z(t[r]);)r++;if((e=45===t[r])?r++:43===t[r]&&r++,48!==t[r]||120!==t[r+1]&&88!==t[r+1])for(;r=St&&(n>St||u>wt+e))return null;n=10*n+u|0,a=!1}else for(r+=2;r"),e.short_src,e.linedefined):Q(t,"?")},Ft=function(t){var e="PANIC: unprotected error in call to Lua API ("+dt(t,-1)+")";throw new Error(e)},jt=function(t,e,r){var n=new T;return w(t,0,n)?(y(t,yt("n"),n),Rt(n.namewhat,yt("method"))&&0===--e?zt(t,yt("calling '%s' on bad self (%s)"),n.name,r):(null===n.name&&(n.name=Gt(t,n)?bt(t,-1):yt("?")),zt(t,yt("bad argument #%d to '%s' (%s)"),e,n.name,r))):zt(t,yt("bad argument #%d (%s)"),e,r)},Ht=function(t,e,r){var n;n=he(t,e,Ct)===d?bt(t,-1):Ot(t,e)===p?yt("light userdata",!0):Wt(t,e);var a=q(t,yt("%s expected, got %s"),r,n);return jt(t,e,a)},Xt=function(t,e){var r=new T;w(t,e,r)&&(y(t,yt("Sl",!0),r),r.currentline>0)?q(t,yt("%s:%d: "),r.short_src,r.currentline):et(t,yt(""))},zt=function(t,e){Xt(t,1);for(var r=arguments.length,n=new Array(r>2?r-2:0),a=2;a0&&(e=Nt(e),ae(t,r).set(e.subarray(0,r)),ie(t,r))},oe=function(t,e){e=Nt(e),se(t,e,e.length)},le=function(t){$(t.L,t.b,t.n),t.n=0,t.b=Vt},ie=function(t,e){t.n+=e},ce=function(t,e,r,n){return Ot(t,r)<=0?n:e(t,r)},fe=function(t,e){var r=e.string;return e.string=null,r},_e=function(t,e,r,n,a){return K(t,fe,{string:e},n,a)},pe=function(t,e,r,n){return _e(t,e,0,n,null)},ve=function(t,e){return pe(t,e,e.length,e)},he=function(t,e,r){if(S(t,e)){et(t,r);var n=ut(t,-2);return n===v?z(t,2):it(t,-2),n}return v},Le=function(t,e,r){return e=x(t,e),he(t,e,r)!==v&&(rt(t,e),k(t,1,1),!0)},de=yt("%I"),Ae=yt("%f"),ge=function(t,e,r){var n=r>>>0,a=e.length,u=t.length+1-a;t:for(;n0){var n=r.n;return r.n=0,r.f=r.f.subarray(r.pos),r.buff.subarray(0,n)}var a=r.f;return r.f=null,a};a=function(t){return t.pos=200&&o.status<=299))return a.err=o.status,ke(t,"open",u,{message:"".concat(o.status,": ").concat(o.statusText)});"string"==typeof o.response?a.f=yt(o.response):a.f=new Uint8Array(o.response);var l=Ee(a);l.c===f[0]&&e||l.skipped&&(a.buff[a.n++]=10),null!==l.c&&(a.buff[a.n++]=l.c);var i=K(t,me,a,bt(t,-1),r),c=a.err;return c?(pt(t,u),ke(t,"read",u,c)):(it(t,u),i)};var Ue=function(t,e){return u(t,e,null)},Ne=function(t,e,r){var n=mt(t);72!=r&&zt(t,yt("core and library have incompatible numeric types")),n!=mt(null)?zt(t,yt("multiple Lua VMs detected")):n!==e&&zt(t,yt("version mismatch: app. needs %f, Lua core provides %f"),e,n)};t.exports.LUA_ERRFILE=wt,t.exports.LUA_FILEHANDLE=Pt,t.exports.LUA_LOADED_TABLE=It,t.exports.LUA_NOREF=-2,t.exports.LUA_PRELOAD_TABLE=Mt,t.exports.LUA_REFNIL=-1,t.exports.luaL_Buffer=Bt,t.exports.luaL_addchar=function(t,e){ae(t,1),t.b[t.n++]=e},t.exports.luaL_addlstring=se,t.exports.luaL_addsize=ie,t.exports.luaL_addstring=oe,t.exports.luaL_addvalue=function(t){var e=t.L,r=bt(e,-1);se(t,r,r.length),z(e,1)},t.exports.luaL_argcheck=function(t,e,r,n){e||jt(t,r,n)},t.exports.luaL_argerror=jt,t.exports.luaL_buffinit=ue,t.exports.luaL_buffinitsize=function(t,e,r){return ue(t,e),ae(e,r)},t.exports.luaL_callmeta=Le,t.exports.luaL_checkany=function(t,e){Ot(t,e)===h&&jt(t,e,yt("value expected",!0))},t.exports.luaL_checkinteger=ne,t.exports.luaL_checklstring=Qt,t.exports.luaL_checknumber=re,t.exports.luaL_checkoption=function(t,e,r,n){for(var a=null!==r?ee(t,e,r):$t(t,e),u=0;n[u];u++)if(Rt(n[u],a))return u;return jt(t,e,q(t,yt("invalid option '%s'"),a))},t.exports.luaL_checkstack=be,t.exports.luaL_checkstring=$t,t.exports.luaL_checktype=function(t,e,r){Ot(t,e)!==r&&qt(t,e,r)},t.exports.luaL_checkudata=function(t,e,r){var n=Zt(t,e,r);return null===n&&Ht(t,e,r),n},t.exports.luaL_checkversion=function(t){Ne(t,g,72)},t.exports.luaL_checkversion_=Ne,t.exports.luaL_dofile=function(t,e){return Ue(t,e)||X(t,0,i,0)},t.exports.luaL_dostring=function(t,e){return ve(t,e)||X(t,0,i,0)},t.exports.luaL_error=zt,t.exports.luaL_execresult=function(t,e){var r,n;if(null===e)return Y(t,1),Q(t,"exit"),W(t,0),3;if(e.status)r="exit",n=e.status;else{if(!e.signal)return Yt(t,0,null,e);r="signal",n=e.signal}return tt(t),Q(t,r),W(t,n),3},t.exports.luaL_fileresult=Yt,t.exports.luaL_getmetafield=he,t.exports.luaL_getmetatable=Jt,t.exports.luaL_getsubtable=Te,t.exports.luaL_gsub=function(t,e,r,n){var a,u=new Bt;for(ue(t,u);(a=ge(e,r))>=0;)se(u,e,a),oe(u,n),e=e.subarray(a+r.length);return oe(u,e),le(u),bt(t,-1)},t.exports.luaL_len=function(t,e){G(t,e);var r=Lt(t,-1);return!1===r&&zt(t,yt("object length is not an integer",!0)),z(t,1),r},t.exports.luaL_loadbuffer=pe,t.exports.luaL_loadbufferx=_e,t.exports.luaL_loadfile=Ue,t.exports.luaL_loadfilex=u,t.exports.luaL_loadstring=ve,t.exports.luaL_newlib=function(t,e){U(t),xe(t,e,0)},t.exports.luaL_newlibtable=function(t){U(t)},t.exports.luaL_newmetatable=function(t,e){return Jt(t,e)!==v?0:(z(t,1),U(t,0,2),et(t,e),ct(t,-2,Ct),rt(t,-1),ct(t,c,e),1)},t.exports.luaL_newstate=function(){var t=F();return t&&b(t,Ft),t},t.exports.luaL_opt=ce,t.exports.luaL_optinteger=function(t,e,r){return ce(t,ne,e,r)},t.exports.luaL_optlstring=te,t.exports.luaL_optnumber=function(t,e,r){return ce(t,re,e,r)},t.exports.luaL_optstring=ee,t.exports.luaL_prepbuffer=function(t){return ae(t,s)},t.exports.luaL_prepbuffsize=ae,t.exports.luaL_pushresult=le,t.exports.luaL_pushresultsize=function(t,e){ie(t,e),le(t)},t.exports.luaL_ref=function(t,e){var r;return C(t,-1)?(z(t,1),-1):(e=x(t,e),st(t,e,0),r=ht(t,-1),z(t,1),0!==r?(st(t,e,r),lt(t,e,0)):r=ot(t,e)+1,lt(t,e,r),r)},t.exports.luaL_requiref=function(t,e,r,n){Te(t,c,It),R(t,-1,e),vt(t,-1)||(z(t,1),Z(t,r),et(t,e),k(t,1,1),rt(t,-1),ct(t,-3,e)),it(t,-2),n&&(rt(t,-1),ft(t,e))},t.exports.luaL_setfuncs=xe,t.exports.luaL_setmetatable=function(t,e){Jt(t,e),_t(t,-2)},t.exports.luaL_testudata=Zt,t.exports.luaL_tolstring=function(t,e){if(Le(t,e,Dt))V(t,-1)||zt(t,yt("'__tostring' must return a string"));else switch(Ot(t,e)){case L:P(t,e)?q(t,de,ht(t,e)):q(t,Ae,gt(t,e));break;case d:rt(t,e);break;case _:Q(t,vt(t,e)?"true":"false");break;case v:Q(t,"nil");break;default:var r=he(t,e,Ct),n=r===d?bt(t,-1):Wt(t,e);q(t,yt("%s: %p"),n,xt(t,e)),r!==v&&it(t,-2)}return At(t,-1)},t.exports.luaL_traceback=function(t,e,r,n){var a=new T,u=I(t),s=function(t){for(var e=new T,r=1,n=1;w(t,n,e);)r=n,n*=2;for(;r21?10:-1;for(r&&q(t,yt("%s\n"),r),be(t,10,null),Q(t,"stack traceback:");w(e,n++,a);)0==o--?(Q(t,"\n\t..."),n=s-11+1):(y(e,yt("Slnt",!0),a),q(t,yt("\n\t%s:"),a.short_src),a.currentline>0&&Q(t,"".concat(a.currentline,":")),Q(t," in "),Kt(t,a),a.istailcall&&Q(t,"\n\t(...tail calls..)"),E(t,I(t)-u));E(t,I(t)-u)},t.exports.luaL_typename=Wt,t.exports.luaL_unref=function(t,e,r){r>=0&&(e=x(t,e),st(t,e,0),lt(t,e,r),W(t,r),lt(t,e,0))},t.exports.luaL_where=Xt,t.exports.lua_writestringerror=function(){for(var t=0;te;)delete t.stack[--t.top]},z=function(t,e,r){for(var n=t.top;t.topr+1;)delete t.stack[--t.top]},Y=K+200,J=function(t,e){I(e<=K||e==Y),I(t.stack_last==t.stack.length-V.EXTRA_STACK),t.stack.length=e,t.stack_last=e-V.EXTRA_STACK},Z=function(t,e){var r=t.stack.length;if(r>K)st(t,T);else{var n=t.top+e+V.EXTRA_STACK,a=2*r;a>K&&(a=K),aK?(J(t,Y),R.luaG_runerror(t,U("stack overflow",!0))):J(t,a)}},q=function(t,e){t.stack_last-t.top<=e&&Z(t,e)},W=function(t){var e=function(t){for(var e=t.top,r=t.ci;null!==r;r=r.previous)eK&&(r=K),t.stack.length>K&&V.luaE_freeCI(t),e<=K-V.EXTRA_STACK&&r=r+n;s--)delete t.stack[s];return t.top=r+n,!1;default:var o;if(a<=n)for(o=0;o=t.top?t.stack[r+o]=new P.TValue(d,null):t.stack[r+o].setnilvalue()}}for(var l=r+a,i=t.top;i>=l;i--)delete t.stack[i];return t.top=l,!0},et=function(t,e,r){var n=t.hook;if(n&&t.allowhook){var a=t.ci,u=t.top,s=a.top,o=new E;o.event=e,o.currentline=r,o.i_ci=a,q(t,c),a.top=t.top+c,I(a.top<=t.stack_last),t.allowhook=0,a.callstatus|=V.CIST_HOOKED,n(t,o),I(!t.allowhook),t.allowhook=1,a.top=s,X(t,u),a.callstatus&=~V.CIST_HOOKED}},rt=function(t,e){var r=a;e.l_savedpc++,e.previous.callstatus&V.CIST_LUA&&e.previous.l_code[e.previous.l_savedpc-1].opcode==C.OpCodesI.OP_TAILCALL&&(e.callstatus|=V.CIST_TAIL,r=s),et(t,r,-1),e.l_savedpc--},nt=function(t,e,r){var n,a=e.numparams,u=t.top-r,s=t.top;for(n=0;ne;a--)P.setobjs2s(t,a,a-1);P.setobj2s(t,e,n)},ut=function(t,e,r){++t.nCcalls>=M&&function(t){t.nCcalls===M?R.luaG_runerror(t,U("JS stack overflow",!0)):t.nCcalls>=M+(M>>3)&&st(t,T)}(t),Q(t,e,r)||j.luaV_execute(t),t.nCcalls--},st=function t(e,r){if(e.errorJmp)throw e.errorJmp.status=r,e.errorJmp;var n=e.l_G;if(e.status=r,!n.mainthread.errorJmp){var a=n.panic;throw a&&(z(e,r,e.top),e.ci.top0&&(t!==t.l_G.mainthread?R.luaG_runerror(t,U("attempt to yield across a JS-call boundary",!0)):R.luaG_runerror(t,U("attempt to yield from outside a coroutine",!0))),t.status=O,a.extra=a.funcOff,a.callstatus&V.CIST_LUA?w(t,null===n,"hooks cannot continue after yielding"):(a.c_k=n,null!==n&&(a.c_ctx=r),a.funcOff=t.top-e-1,a.func=t.stack[a.funcOff],st(t,O)),I(a.callstatus&V.CIST_HOOKED),0},vt=function(t,e,r,n,a){var u=t.ci,s=t.allowhook,o=t.nny,l=t.errfunc;t.errfunc=a;var i=ot(t,e,r);return i!==k&&(y.luaF_close(t,n),z(t,i,n),t.ci=u,t.allowhook=s,t.nny=o,W(t)),t.errfunc=l,i},ht=function(t,e,r){t.nny++,ut(t,e,r),t.nny--},Lt=function t(e,r,n){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.z=e,this.buff=new H,this.dyd=new D.Dyndata,this.mode=n,this.name=r},dt=function(t,e,r){e&&-1===m(e,r[0])&&(P.luaO_pushfstring(t,U("attempt to load a %s chunk (mode is '%s')"),r,e),st(t,b))},At=function(t,e){var r,n=e.z.zgetc();n===_[0]?(dt(t,e.mode,U("binary",!0)),r=F.luaU_undump(t,e.z,e.name)):(dt(t,e.mode,U("text",!0)),r=D.luaY_parser(t,e.z,e.buff,e.dyd,e.name,n)),I(r.nupvalues===r.p.upvalues.length),y.luaF_initupvals(t,r)};t.exports.adjust_top=X,t.exports.luaD_call=ut,t.exports.luaD_callnoyield=ht,t.exports.luaD_checkstack=q,t.exports.luaD_growstack=Z,t.exports.luaD_hook=et,t.exports.luaD_inctop=function(t){q(t,1),t.stack[t.top++]=new P.TValue(d,null)},t.exports.luaD_pcall=vt,t.exports.luaD_poscall=$,t.exports.luaD_precall=Q,t.exports.luaD_protectedparser=function(t,e,r,n){var a=new Lt(e,r,n);t.nny++;var u=vt(t,At,a,t.top,t.errfunc);return t.nny--,u},t.exports.luaD_rawrunprotected=ot,t.exports.luaD_reallocstack=J,t.exports.luaD_throw=st,t.exports.lua_isyieldable=function(t){return 0===t.nny},t.exports.lua_resume=function(t,e,r){var n=t.nny;if(t.status===k){if(t.ci!==t.base_ci)return ft(t,"cannot resume non-suspended coroutine",r)}else if(t.status!==O)return ft(t,"cannot resume dead coroutine",r);if(t.nCcalls=e?e.nCcalls+1:1,t.nCcalls>=M)return ft(t,"JS stack overflow",r);t.nny=0,N.api_checknelems(t,t.status===k?r+1:r);var a=ot(t,_t,r);if(-1===a)a=x;else{for(;a>O&&ct(t,a);)a=ot(t,it,a);a>O?(t.status=a,z(t,a,t.top),t.ci.top=t.top):I(a===t.status)}return t.nny=n,t.nCcalls--,I(t.nCcalls===(e?e.nCcalls:0)),a},t.exports.lua_yield=function(t,e){pt(t,e,0,null)},t.exports.lua_yieldk=pt},function(t,e,r){"use strict";function n(t){return(n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var a=r(1),u=a.constant_types,s=u.LUA_TBOOLEAN,o=u.LUA_TCCL,l=u.LUA_TLCF,i=u.LUA_TLCL,c=u.LUA_TLIGHTUSERDATA,f=u.LUA_TLNGSTR,_=u.LUA_TNIL,p=u.LUA_TNUMFLT,v=u.LUA_TNUMINT,h=u.LUA_TSHRSTR,L=u.LUA_TTABLE,d=u.LUA_TTHREAD,A=u.LUA_TUSERDATA,g=a.to_luastring,T=r(4).lua_assert,x=r(11),b=r(6),k=r(10),O=k.luaS_hashlongstr,E=k.TString,m=r(12),U=new WeakMap,N=function(t){var e=U.get(t);return e||(e={},U.set(t,e)),e},R=function(t,e){switch(e.type){case _:return x.luaG_runerror(t,g("table index is nil",!0));case p:if(isNaN(e.value))return x.luaG_runerror(t,g("table index is NaN",!0));case v:case s:case L:case i:case l:case o:case A:case d:return e.value;case h:case f:return O(e.tsvalue());case c:var r=e.value;switch(n(r)){case"string":return"*"+r;case"number":return"#"+r;case"boolean":return r?"?true":"?false";case"function":return N(r);case"object":if(r instanceof m.lua_State&&r.l_G===t.l_G||r instanceof y||r instanceof b.Udata||r instanceof b.LClosure||r instanceof b.CClosure)return N(r);default:return r}default:throw new Error("unknown key type: "+e.type)}},y=function t(e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.id=e.l_G.id_counter++,this.strong=new Map,this.dead_strong=new Map,this.dead_weak=void 0,this.f=void 0,this.l=void 0,this.metatable=null,this.flags=-1},S=function(t,e,r,n){t.dead_strong.clear(),t.dead_weak=void 0;var a=null,u={key:r,value:n,p:a=t.l,n:void 0};t.f||(t.f=u),a&&(a.n=u),t.strong.set(e,u),t.l=u},w=function(t,e){var r=t.strong.get(e);if(r){r.key.setdeadvalue(),r.value=void 0;var a=r.n,u=r.p;r.p=void 0,u&&(u.n=a),a&&(a.p=u),t.f===r&&(t.f=a),t.l===r&&(t.l=u),t.strong.delete(e),!function(t){return"object"===n(t)?null!==t:"function"==typeof t}(e)?t.dead_strong.set(e,r):(t.dead_weak||(t.dead_weak=new WeakMap),t.dead_weak.set(e,r))}},I=function(t,e){var r=t.strong.get(e);return r?r.value:b.luaO_nilobject},M=function(t,e){return T("number"==typeof e&&(0|e)===e),I(t,e)};t.exports.invalidateTMcache=function(t){t.flags=0},t.exports.luaH_get=function(t,e,r){return T(r instanceof b.TValue),r.ttisnil()||r.ttisfloat()&&isNaN(r.value)?b.luaO_nilobject:I(e,R(t,r))},t.exports.luaH_getint=M,t.exports.luaH_getn=function(t){for(var e=0,r=t.strong.size+1;r-e>1;){var n=Math.floor((e+r)/2);M(t,n).ttisnil()?r=n:e=n}return e},t.exports.luaH_getstr=function(t,e){return T(e instanceof E),I(t,O(e))},t.exports.luaH_setfrom=function(t,e,r,n){T(r instanceof b.TValue);var a=R(t,r);if(n.ttisnil())w(e,a);else{var u=e.strong.get(a);if(u)u.value.setfrom(n);else{var s,o=r.value;s=r.ttisfloat()&&(0|o)===o?new b.TValue(v,o):new b.TValue(r.type,o);var l=new b.TValue(n.type,n.value);S(e,a,s,l)}}},t.exports.luaH_setint=function(t,e,r){T("number"==typeof e&&(0|e)===e&&r instanceof b.TValue);var n=e;if(r.ttisnil())w(t,n);else{var a=t.strong.get(n);if(a)a.value.setfrom(r);else{var u=new b.TValue(v,e),s=new b.TValue(r.type,r.value);S(t,n,u,s)}}},t.exports.luaH_new=function(t){return new y(t)},t.exports.luaH_next=function(t,e,r){var n,a=t.stack[r];if(a.type===_){if(!(n=e.f))return!1}else{var u=R(t,a);if(n=e.strong.get(u)){if(!(n=n.n))return!1}else{if(!(n=e.dead_weak&&e.dead_weak.get(u)||e.dead_strong.get(u)))return x.luaG_runerror(t,g("invalid key to 'next'"));do{if(!(n=n.n))return!1}while(n.key.ttisdeadkey())}}return b.setobj2s(t,r,n.key),b.setobj2s(t,r+1,n.value),!0},t.exports.Table=y},function(t,e,r){"use strict";function n(t,e){for(var r=0;r=t.l_base-t.funcOff-r?null:{pos:t.funcOff+r+e,name:A("(*vararg)",!0)}}(e,-r);n=e.l_base,a=E.luaF_getlocalname(e.func.value.p,r,I(e))}else n=e.funcOff+1;if(null===a){if(!((e===t.ci?t.top:e.next.funcOff)-n>=r&&r>0))return null;a=A("(*temporary)",!0)}return{pos:n+(r-1),name:a}},V=function(t,e){if(null===e||e instanceof U.CClosure)t.source=A("=[JS]",!0),t.linedefined=-1,t.lastlinedefined=-1,t.what=A("J",!0);else{var r=e.p;t.source=r.source?r.source.getstr():A("=?",!0),t.linedefined=r.linedefined,t.lastlinedefined=r.lastlinedefined,t.what=0===t.linedefined?A("main",!0):A("Lua",!0)}t.short_src=U.luaO_chunkid(t.source,b)},B=function(t,e){var r={name:null,funcname:null};return null===e?null:e.callstatus&R.CIST_FIN?(r.name=A("__gc",!0),r.funcname=A("metamethod",!0),r):!(e.callstatus&R.CIST_TAIL)&&e.previous.callstatus&R.CIST_LUA?j(t,e.previous):null},G=function(t,e,r){var n={name:null,funcname:null};if(N.ISK(r)){var a=t.k[N.INDEXK(r)];if(a.ttisstring())return n.name=a.svalue(),n}else{var u=F(t,e,r);if(u&&99===u.funcname[0])return u}return n.name=A("?",!0),n},K=function(t,e){return t=l+2&&(n=K(s,a));break;case u.OP_CALL:case u.OP_TAILCALL:r>=l&&(n=K(s,a));break;case u.OP_JMP:var c=s+1+o.sBx;sa&&(a=c);break;default:N.testAMode(o.opcode)&&r===l&&(n=K(s,a))}}return n}(e,r,n),s=N.OpCodesI;if(-1!==u){var o=e.code[u];switch(o.opcode){case s.OP_MOVE:var l=o.B;if(l2?n-2:0),u=2;u0;e=e.subarray(1))switch(e[0]){case 83:V(r,n);break;case 108:r.currentline=a&&a.callstatus&R.CIST_LUA?M(a):-1;break;case 117:r.nups=null===n?0:n.nupvalues,null===n||n instanceof U.CClosure?(r.isvararg=!0,r.nparams=0):(r.isvararg=n.p.is_vararg,r.nparams=n.p.numparams);break;case 116:r.istailcall=a?a.callstatus&R.CIST_TAIL:0;break;case 110:var s=B(t,a);null===s?(r.namewhat=A("",!0),r.name=null):(r.namewhat=s.funcname,r.name=s.name);break;case 76:case 102:break;default:u=0}return u}(t,e,r,a=s.ttisclosure()?s.value:null,u),d(e,102)>=0&&(U.pushobj2s(t,s),T(t,t.top<=t.ci.top,"stack overflow")),P(t),d(e,76)>=0&&function(t,e){if(null===e||e instanceof U.CClosure)t.stack[t.top]=new U.TValue(c,null),k.api_incr_top(t);else{var r=e.p.lineinfo,n=y.luaH_new(t);t.stack[t.top]=new U.TValue(f,n),k.api_incr_top(t);for(var a=new U.TValue(i,!0),u=0;u0&&n!==t.base_ci;n=n.previous)e--;return 0===e&&n!==t.base_ci?(a=1,r.i_ci=n):a=0,a},t.exports.lua_sethook=function(t,e,r,n){null!==e&&0!==r||(r=0,e=null),t.ci.callstatus&R.CIST_LUA&&(t.oldpc=t.ci.l_savedpc),t.hook=e,t.basehookcount=n,t.hookcount=t.basehookcount,t.hookmask=r},t.exports.lua_setlocal=function(t,e,r){var n;P(t);var a=D(t,e.i_ci,r);return a?(n=a.name,U.setobjs2s(t,a.pos,t.top-1),delete t.stack[--t.top]):n=null,P(t),n}},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var a=r(1),u=a.LUA_MINSTACK,s=a.LUA_RIDX_GLOBALS,o=a.LUA_RIDX_MAINTHREAD,l=a.constant_types,i=l.LUA_NUMTAGS,c=l.LUA_TNIL,f=l.LUA_TTABLE,_=l.LUA_TTHREAD,p=a.thread_status.LUA_OK,v=r(6),h=r(8),L=r(19),d=r(9),A=r(14),g=2*u,T=function t(){n(this,t),this.func=null,this.funcOff=NaN,this.top=NaN,this.previous=null,this.next=null,this.l_base=NaN,this.l_code=null,this.l_savedpc=NaN,this.c_k=null,this.c_old_errfunc=null,this.c_ctx=null,this.nresults=NaN,this.callstatus=NaN},x=function t(e){n(this,t),this.id=e.id_counter++,this.base_ci=new T,this.top=NaN,this.stack_last=NaN,this.oldpc=NaN,this.l_G=e,this.stack=null,this.ci=null,this.errorJmp=null,this.nCcalls=0,this.hook=null,this.hookmask=0,this.basehookcount=0,this.allowhook=1,this.hookcount=this.basehookcount,this.nny=1,this.status=p,this.errfunc=0},b=function(t){t.ci.next=null},k=function(t,e){t.stack=new Array(g),t.top=0,t.stack_last=g-5;var r=t.base_ci;r.next=r.previous=null,r.callstatus=0,r.funcOff=t.top,r.func=t.stack[t.top],t.stack[t.top++]=new v.TValue(c,null),r.top=t.top+u,t.ci=r},O=function(t){t.ci=t.base_ci,b(t),t.stack=null},E=function(t){var e=t.l_G;k(t),function(t,e){var r=d.luaH_new(t);e.l_registry.sethvalue(r),d.luaH_setint(r,o,new v.TValue(_,t)),d.luaH_setint(r,s,new v.TValue(f,d.luaH_new(t)))}(t,e),A.luaT_init(t),e.version=L.lua_version(null)};t.exports.lua_State=x,t.exports.CallInfo=T,t.exports.CIST_OAH=1,t.exports.CIST_LUA=2,t.exports.CIST_HOOKED=4,t.exports.CIST_FRESH=8,t.exports.CIST_YPCALL=16,t.exports.CIST_TAIL=32,t.exports.CIST_HOOKYIELD=64,t.exports.CIST_LEQ=128,t.exports.CIST_FIN=256,t.exports.EXTRA_STACK=5,t.exports.lua_close=function(t){!function(t){O(t)}(t=t.l_G.mainthread)},t.exports.lua_newstate=function(){var t=new function t(){n(this,t),this.id_counter=1,this.ids=new WeakMap,this.mainthread=null,this.l_registry=new v.TValue(c,null),this.panic=null,this.atnativeerror=null,this.version=null,this.tmname=new Array(A.TMS.TM_N),this.mt=new Array(i)},e=new x(t);return t.mainthread=e,h.luaD_rawrunprotected(e,E,null)!==p&&(e=null),e},t.exports.lua_newthread=function(t){var e=t.l_G,r=new x(e);return t.stack[t.top]=new v.TValue(_,r),L.api_incr_top(t),r.hookmask=t.hookmask,r.basehookcount=t.basehookcount,r.hook=t.hook,r.hookcount=r.basehookcount,k(r),r},t.exports.luaE_extendCI=function(t){var e=new T;return t.ci.next=e,e.previous=t.ci,e.next=null,t.ci=e,e},t.exports.luaE_freeCI=b,t.exports.luaE_freethread=function(t,e){O(e)}},function(t,e,r){"use strict";var n=r(1).constant_types.LUA_TNIL,a=r(6);t.exports.MAXUPVAL=255,t.exports.Proto=function t(e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.id=e.l_G.id_counter++,this.k=[],this.p=[],this.code=[],this.cache=null,this.lineinfo=[],this.upvalues=[],this.numparams=0,this.is_vararg=!1,this.maxstacksize=0,this.locvars=[],this.linedefined=0,this.lastlinedefined=0,this.source=null},t.exports.luaF_findupval=function(t,e){return t.stack[e]},t.exports.luaF_close=function(t,e){for(var r=e;r=0&&(r=!0))}return{stopnow:r,ilimit:n}},zt=function t(e,r){if(e.ttisfloat()){var n=e.value,a=Math.floor(n);if(n!==a){if(0===r)return!1;r>1&&(a+=1)}return xt(a)}if(e.ttisinteger())return e.value;if(se(e)){var u=new Et.TValue;if(Et.luaO_str2num(e.svalue(),u)===e.vslen()+1)return t(u,r)}return!1},Yt=function(t){return t.ttisinteger()?t.value:zt(t,0)},Jt=function(t){if(t.ttnov()===p)return t.value;if(se(t)){var e=new Et.TValue;if(Et.luaO_str2num(t.svalue(),e)===t.vslen()+1)return e.value}return!1},Zt=function(t,e){return t.value>>16&65535)*n+r*(e>>>16&65535)<<16>>>0)|0},te=function(t,e,r){return 0===r&&Pt.luaG_runerror(t,g("attempt to divide by zero")),0|Math.floor(e/r)},ee=function(t,e,r){return 0===r&&Pt.luaG_runerror(t,g("attempt to perform 'n%%0'")),e-Math.floor(e/r)*r|0},re=function(t,e){return e<0?e<=-32?0:t>>>-e:e>=32?0:t<0)},ce=function(t,e){kt(e>=2);do{var r=t.top,n=2;if((t.stack[r-2].ttisstring()||ue(t.stack[r-2]))&&oe(t,r-1))if(le(t.stack[r-1]))oe(t,r-2);else if(le(t.stack[r-2]))Et.setobjs2s(t,r-2,r-1);else{var a=t.stack[r-1].vslen();for(n=1;nr-(n-1);)delete t.stack[--t.top]}while(e>1)},fe=function(t,e,r,n){for(var a=0;a<2e3;a++){var u=void 0;if(e.ttistable()){var s=Mt.luaH_get(t,e.value,r);if(!s.ttisnil())return void Et.setobj2s(t,n,s);if(null===(u=It.fasttm(t,e.value.metatable,It.TMS.TM_INDEX)))return void t.stack[n].setnilvalue()}else(u=It.luaT_gettmbyobj(t,e,It.TMS.TM_INDEX)).ttisnil()&&Pt.luaG_typeerror(t,e,g("index",!0));if(u.ttisfunction())return void It.luaT_callTM(t,u,e,r,t.stack[n],1);e=u}Pt.luaG_runerror(t,g("'__index' chain too long; possible loop",!0))},_e=function(t,e,r,n){for(var a=0;a<2e3;a++){var u=void 0;if(e.ttistable()){var s=e.value;if(!Mt.luaH_get(t,s,r).ttisnil()||null===(u=It.fasttm(t,s.metatable,It.TMS.TM_NEWINDEX)))return Mt.luaH_setfrom(t,s,r,n),void Mt.invalidateTMcache(s)}else(u=It.luaT_gettmbyobj(t,e,It.TMS.TM_NEWINDEX)).ttisnil()&&Pt.luaG_typeerror(t,e,g("index",!0));if(u.ttisfunction())return void It.luaT_callTM(t,u,e,r,n,0);e=u}Pt.luaG_runerror(t,g("'__newindex' chain too long; possible loop",!0))};t.exports.cvt2str=ue,t.exports.cvt2num=se,t.exports.luaV_gettable=fe,t.exports.luaV_concat=ce,t.exports.luaV_div=te,t.exports.luaV_equalobj=Ht,t.exports.luaV_execute=function(t){var e=t.ci;e.callstatus|=Ut.CIST_FRESH;t:for(;;){kt(e===t.ci);var r=e.func.value,n=r.p.k,o=e.l_base,l=e.l_code[e.l_savedpc++];t.hookmask&(a|u)&&Pt.luaG_traceexec(t);var i=Ct(0,o,l);switch(l.opcode){case W:Et.setobjs2s(t,i,Dt(0,o,l));break;case z:var c=n[l.Bx];Et.setobj2s(t,i,c);break;case Y:kt(e.l_code[e.l_savedpc].opcode===P);var f=n[e.l_code[e.l_savedpc++].Ax];Et.setobj2s(t,i,f);break;case X:t.stack[i].setbvalue(0!==l.B),0!==l.C&&e.l_savedpc++;break;case J:for(var _=0;_<=l.B;_++)t.stack[i+_].setnilvalue();break;case G:var p=l.B;Et.setobj2s(t,i,r.upvals[p]);break;case B:var v=r.upvals[l.B],h=Bt(t,o,n,l);fe(t,v,h,i);break;case V:var L=t.stack[Dt(0,o,l)],d=Bt(t,o,n,l);fe(t,L,d,i);break;case st:var A=r.upvals[l.A],T=Vt(t,o,n,l),x=Bt(t,o,n,l);_e(t,A,T,x);break;case ot:r.upvals[l.B].setfrom(t.stack[i]);break;case ut:var b=t.stack[i],O=Vt(t,o,n,l),At=Bt(t,o,n,l);_e(t,b,O,At);break;case $:t.stack[i].sethvalue(Mt.luaH_new(t));break;case nt:var gt=Dt(0,o,l),Tt=Bt(t,o,n,l);Et.setobjs2s(t,i+1,gt),fe(t,t.stack[gt],Tt,i);break;case E:var xt=Vt(t,o,n,l),bt=Bt(t,o,n,l),Nt=void 0,Rt=void 0;xt.ttisinteger()&&bt.ttisinteger()?t.stack[i].setivalue(xt.value+bt.value|0):!1!==(Nt=Jt(xt))&&!1!==(Rt=Jt(bt))?t.stack[i].setfltvalue(Nt+Rt):It.luaT_trybinTM(t,xt,bt,t.stack[i],It.TMS.TM_ADD);break;case ct:var yt=Vt(t,o,n,l),St=Bt(t,o,n,l),zt=void 0,Zt=void 0;yt.ttisinteger()&&St.ttisinteger()?t.stack[i].setivalue(yt.value-St.value|0):!1!==(zt=Jt(yt))&&!1!==(Zt=Jt(St))?t.stack[i].setfltvalue(zt-Zt):It.luaT_trybinTM(t,yt,St,t.stack[i],It.TMS.TM_SUB);break;case Q:var qt=Vt(t,o,n,l),Wt=Bt(t,o,n,l),ue=void 0,se=void 0;qt.ttisinteger()&&Wt.ttisinteger()?t.stack[i].setivalue($t(qt.value,Wt.value)):!1!==(ue=Jt(qt))&&!1!==(se=Jt(Wt))?t.stack[i].setfltvalue(ue*se):It.luaT_trybinTM(t,qt,Wt,t.stack[i],It.TMS.TM_MUL);break;case q:var oe=Vt(t,o,n,l),le=Bt(t,o,n,l),ie=void 0,pe=void 0;oe.ttisinteger()&&le.ttisinteger()?t.stack[i].setivalue(ee(t,oe.value,le.value)):!1!==(ie=Jt(oe))&&!1!==(pe=Jt(le))?t.stack[i].setfltvalue(Ot(t,ie,pe)):It.luaT_trybinTM(t,oe,le,t.stack[i],It.TMS.TM_MOD);break;case et:var ve,he=Vt(t,o,n,l),Le=Bt(t,o,n,l),de=void 0;!1!==(ve=Jt(he))&&!1!==(de=Jt(Le))?t.stack[i].setfltvalue(Math.pow(ve,de)):It.luaT_trybinTM(t,he,Le,t.stack[i],It.TMS.TM_POW);break;case I:var Ae,ge=Vt(t,o,n,l),Te=Bt(t,o,n,l),xe=void 0;!1!==(Ae=Jt(ge))&&!1!==(xe=Jt(Te))?t.stack[i].setfltvalue(Ae/xe):It.luaT_trybinTM(t,ge,Te,t.stack[i],It.TMS.TM_DIV);break;case K:var be=Vt(t,o,n,l),ke=Bt(t,o,n,l),Oe=void 0,Ee=void 0;be.ttisinteger()&&ke.ttisinteger()?t.stack[i].setivalue(te(t,be.value,ke.value)):!1!==(Oe=Jt(be))&&!1!==(Ee=Jt(ke))?t.stack[i].setfltvalue(Math.floor(Oe/Ee)):It.luaT_trybinTM(t,be,ke,t.stack[i],It.TMS.TM_IDIV);break;case m:var me,Ue=Vt(t,o,n,l),Ne=Bt(t,o,n,l),Re=void 0;!1!==(me=Yt(Ue))&&!1!==(Re=Yt(Ne))?t.stack[i].setivalue(me&Re):It.luaT_trybinTM(t,Ue,Ne,t.stack[i],It.TMS.TM_BAND);break;case N:var ye,Se=Vt(t,o,n,l),we=Bt(t,o,n,l),Ie=void 0;!1!==(ye=Yt(Se))&&!1!==(Ie=Yt(we))?t.stack[i].setivalue(ye|Ie):It.luaT_trybinTM(t,Se,we,t.stack[i],It.TMS.TM_BOR);break;case R:var Me,Pe=Vt(t,o,n,l),Ce=Bt(t,o,n,l),De=void 0;!1!==(Me=Yt(Pe))&&!1!==(De=Yt(Ce))?t.stack[i].setivalue(Me^De):It.luaT_trybinTM(t,Pe,Ce,t.stack[i],It.TMS.TM_BXOR);break;case lt:var Ve,Be=Vt(t,o,n,l),Ge=Bt(t,o,n,l),Ke=void 0;!1!==(Ve=Yt(Be))&&!1!==(Ke=Yt(Ge))?t.stack[i].setivalue(re(Ve,Ke)):It.luaT_trybinTM(t,Be,Ge,t.stack[i],It.TMS.TM_SHL);break;case it:var Fe,je=Vt(t,o,n,l),He=Bt(t,o,n,l),Xe=void 0;!1!==(Fe=Yt(je))&&!1!==(Xe=Yt(He))?t.stack[i].setivalue(re(Fe,-Xe)):It.luaT_trybinTM(t,je,He,t.stack[i],It.TMS.TM_SHR);break;case Lt:var ze=t.stack[Dt(0,o,l)],Ye=void 0;ze.ttisinteger()?t.stack[i].setivalue(0|-ze.value):!1!==(Ye=Jt(ze))?t.stack[i].setfltvalue(-Ye):It.luaT_trybinTM(t,ze,ze,t.stack[i],It.TMS.TM_UNM);break;case U:var Je=t.stack[Dt(0,o,l)];Je.ttisinteger()?t.stack[i].setivalue(~Je.value):It.luaT_trybinTM(t,Je,Je,t.stack[i],It.TMS.TM_BNOT);break;case tt:var Ze=t.stack[Dt(0,o,l)];t.stack[i].setbvalue(Ze.l_isfalse());break;case H:Qt(t,t.stack[i],t.stack[Dt(0,o,l)]);break;case w:var qe=l.B,We=l.C;t.top=o+We+1,ce(t,We-qe+1);var Qe=o+qe;Et.setobjs2s(t,i,Qe),wt.adjust_top(t,e.top);break;case F:Gt(t,e,l,0);break;case M:Ht(t,Vt(t,o,n,l),Bt(t,o,n,l))!==l.A?e.l_savedpc++:Kt(t,e);break;case Z:Ft(t,Vt(t,o,n,l),Bt(t,o,n,l))!==l.A?e.l_savedpc++:Kt(t,e);break;case j:jt(t,Vt(t,o,n,l),Bt(t,o,n,l))!==l.A?e.l_savedpc++:Kt(t,e);break;case _t:(l.C?t.stack[i].l_isfalse():!t.stack[i].l_isfalse())?e.l_savedpc++:Kt(t,e);break;case pt:var $e=Dt(0,o,l),tr=t.stack[$e];(l.C?tr.l_isfalse():!tr.l_isfalse())?e.l_savedpc++:(Et.setobjs2s(t,i,$e),Kt(t,e));break;case y:var er=l.B,rr=l.C-1;if(0!==er&&wt.adjust_top(t,i+er),!wt.luaD_precall(t,i,rr)){e=t.ci;continue t}rr>=0&&wt.adjust_top(t,e.top);break;case ft:var nr=l.B;if(0!==nr&&wt.adjust_top(t,i+nr),!wt.luaD_precall(t,i,s)){var ar=t.ci,ur=ar.previous,sr=ar.func,or=ar.funcOff,lr=ur.funcOff,ir=ar.l_base+sr.value.p.numparams;r.p.p.length>0&&mt.luaF_close(t,ur.l_base);for(var cr=0;or+cr0&&mt.luaF_close(t,o);var fr=wt.luaD_poscall(t,e,i,0!==l.B?l.B-1:t.top-i);if(e.callstatus&Ut.CIST_FRESH)return;e=t.ci,fr&&wt.adjust_top(t,e.top),kt(e.callstatus&Ut.CIST_LUA),kt(e.l_code[e.l_savedpc-1].opcode===y);continue t;case C:if(t.stack[i].ttisinteger()){var _r=t.stack[i+2].value,pr=t.stack[i].value+_r|0,vr=t.stack[i+1].value;(0<_r?pr<=vr:vr<=pr)&&(e.l_savedpc+=l.sBx,t.stack[i].chgivalue(pr),t.stack[i+3].setivalue(pr))}else{var hr=t.stack[i+2].value,Lr=t.stack[i].value+hr,dr=t.stack[i+1].value;(00;Ur--)Mt.luaH_setint(Rr,yr--,t.stack[i+Ur]);wt.adjust_top(t,e.top);break;case S:var Sr=r.p.p[l.Bx],wr=ne(Sr,r.upvals,t.stack,o);null===wr?ae(t,Sr,r.upvals,o,i):t.stack[i].setclLvalue(wr);break;case dt:var Ir=l.B-1,Mr=o-e.funcOff-r.p.numparams-1,Pr=void 0;for(Mr<0&&(Mr=0),Ir<0&&(Ir=Mr,wt.luaD_checkstack(t,Mr),wt.adjust_top(t,i+Mr)),Pr=0;Pr1&&(t.top=s-1,ce(t,o)),Et.setobjs2s(t,e.l_base+n.A,t.top-1),wt.adjust_top(t,e.top);break;case vt:kt(e.l_code[e.l_savedpc].opcode===ht),wt.adjust_top(t,e.top);break;case y:n.C-1>=0&&wt.adjust_top(t,e.top)}},t.exports.luaV_imul=$t,t.exports.luaV_lessequal=jt,t.exports.luaV_lessthan=Ft,t.exports.luaV_mod=ee,t.exports.luaV_objlen=Qt,t.exports.luaV_rawequalobj=function(t,e){return Ht(null,t,e)},t.exports.luaV_shiftl=re,t.exports.luaV_tointeger=zt,t.exports.settable=_e,t.exports.tointeger=Yt,t.exports.tonumber=Jt},function(t,e,r){"use strict";var n=[96,113,65,84,80,80,92,108,60,16,60,84,108,124,124,124,124,124,124,124,124,124,124,124,124,96,96,96,96,104,34,188,188,188,132,228,84,84,16,98,98,4,98,20,81,80,23],a=function(t,e){return~(-1<>0&a(6,0),A:t>>6&a(8,0),B:t>>23&a(9,0),C:t>>14&a(9,0),Bx:t>>14&a(18,0),Ax:t>>6&a(26,0),sBx:(t>>14&a(18,0))-131071};var e=t.code;return t.opcode=e>>0&a(6,0),t.A=e>>6&a(8,0),t.B=e>>23&a(9,0),t.C=e>>14&a(9,0),t.Bx=e>>14&a(18,0),t.Ax=e>>6&a(26,0),t.sBx=(e>>14&a(18,0))-131071,t};t.exports.BITRK=256,t.exports.CREATE_ABC=function(t,e,r,n){return l(t<<0|e<<6|r<<23|n<<14)},t.exports.CREATE_ABx=function(t,e,r){return l(t<<0|e<<6|r<<14)},t.exports.CREATE_Ax=function(t,e){return l(t<<0|e<<6)},t.exports.GET_OPCODE=function(t){return t.opcode},t.exports.GETARG_A=function(t){return t.A},t.exports.GETARG_B=function(t){return t.B},t.exports.GETARG_C=function(t){return t.C},t.exports.GETARG_Bx=function(t){return t.Bx},t.exports.GETARG_Ax=function(t){return t.Ax},t.exports.GETARG_sBx=function(t){return t.sBx},t.exports.INDEXK=function(t){return-257&t},t.exports.ISK=function(t){return 256&t},t.exports.LFIELDS_PER_FLUSH=50,t.exports.MAXARG_A=255,t.exports.MAXARG_Ax=67108863,t.exports.MAXARG_B=511,t.exports.MAXARG_Bx=262143,t.exports.MAXARG_C=511,t.exports.MAXARG_sBx=131071,t.exports.MAXINDEXRK=255,t.exports.NO_REG=255,t.exports.OpArgK=3,t.exports.OpArgN=0,t.exports.OpArgR=2,t.exports.OpArgU=1,t.exports.OpCodes=["MOVE","LOADK","LOADKX","LOADBOOL","LOADNIL","GETUPVAL","GETTABUP","GETTABLE","SETTABUP","SETUPVAL","SETTABLE","NEWTABLE","SELF","ADD","SUB","MUL","MOD","POW","DIV","IDIV","BAND","BOR","BXOR","SHL","SHR","UNM","BNOT","NOT","LEN","CONCAT","JMP","EQ","LT","LE","TEST","TESTSET","CALL","TAILCALL","RETURN","FORLOOP","FORPREP","TFORCALL","TFORLOOP","SETLIST","CLOSURE","VARARG","EXTRAARG"],t.exports.OpCodesI={OP_MOVE:0,OP_LOADK:1,OP_LOADKX:2,OP_LOADBOOL:3,OP_LOADNIL:4,OP_GETUPVAL:5,OP_GETTABUP:6,OP_GETTABLE:7,OP_SETTABUP:8,OP_SETUPVAL:9,OP_SETTABLE:10,OP_NEWTABLE:11,OP_SELF:12,OP_ADD:13,OP_SUB:14,OP_MUL:15,OP_MOD:16,OP_POW:17,OP_DIV:18,OP_IDIV:19,OP_BAND:20,OP_BOR:21,OP_BXOR:22,OP_SHL:23,OP_SHR:24,OP_UNM:25,OP_BNOT:26,OP_NOT:27,OP_LEN:28,OP_CONCAT:29,OP_JMP:30,OP_EQ:31,OP_LT:32,OP_LE:33,OP_TEST:34,OP_TESTSET:35,OP_CALL:36,OP_TAILCALL:37,OP_RETURN:38,OP_FORLOOP:39,OP_FORPREP:40,OP_TFORCALL:41,OP_TFORLOOP:42,OP_SETLIST:43,OP_CLOSURE:44,OP_VARARG:45,OP_EXTRAARG:46},t.exports.POS_A=6,t.exports.POS_Ax=6,t.exports.POS_B=23,t.exports.POS_Bx=14,t.exports.POS_C=14,t.exports.POS_OP=0,t.exports.RKASK=function(t){return 256|t},t.exports.SETARG_A=function(t,e){return s(t,e,6,8)},t.exports.SETARG_Ax=function(t,e){return s(t,e,6,26)},t.exports.SETARG_B=function(t,e){return s(t,e,23,9)},t.exports.SETARG_Bx=o,t.exports.SETARG_C=function(t,e){return s(t,e,14,9)},t.exports.SETARG_sBx=function(t,e){return o(t,e+131071)},t.exports.SET_OPCODE=function(t,e){return t.code=t.code&u(6,0)|e<<0&a(6,0),l(t)},t.exports.SIZE_A=8,t.exports.SIZE_Ax=26,t.exports.SIZE_B=9,t.exports.SIZE_Bx=18,t.exports.SIZE_C=9,t.exports.SIZE_OP=6,t.exports.fullins=l,t.exports.getBMode=function(t){return n[t]>>4&3},t.exports.getCMode=function(t){return n[t]>>2&3},t.exports.getOpMode=function(t){return 3&n[t]},t.exports.iABC=0,t.exports.iABx=1,t.exports.iAsBx=2,t.exports.iAx=3,t.exports.testAMode=function(t){return 64&n[t]},t.exports.testTMode=function(t){return 128&n[t]}},function(t,e,r){"use strict";var n=r(2),a="_"+n.LUA_VERSION_MAJOR+"_"+n.LUA_VERSION_MINOR;t.exports.LUA_VERSUFFIX=a,t.exports.lua_assert=function(t){},t.exports.luaopen_base=r(24).luaopen_base;t.exports.LUA_COLIBNAME="coroutine",t.exports.luaopen_coroutine=r(25).luaopen_coroutine;t.exports.LUA_TABLIBNAME="table",t.exports.luaopen_table=r(26).luaopen_table;t.exports.LUA_OSLIBNAME="os",t.exports.luaopen_os=r(27).luaopen_os;t.exports.LUA_STRLIBNAME="string",t.exports.luaopen_string=r(28).luaopen_string;t.exports.LUA_UTF8LIBNAME="utf8",t.exports.luaopen_utf8=r(29).luaopen_utf8;t.exports.LUA_BITLIBNAME="bit32";t.exports.LUA_MATHLIBNAME="math",t.exports.luaopen_math=r(30).luaopen_math;t.exports.LUA_DBLIBNAME="debug",t.exports.luaopen_debug=r(31).luaopen_debug;t.exports.LUA_LOADLIBNAME="package",t.exports.luaopen_package=r(32).luaopen_package;t.exports.LUA_FENGARILIBNAME="fengari",t.exports.luaopen_fengari=r(33).luaopen_fengari;var u=r(39);t.exports.luaL_openlibs=u.luaL_openlibs},function(t,e,r){"use strict";function n(t){return(n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var a=r(0),u=a.lua,s=a.lauxlib,o=a.lualib,l=a.to_luastring,i=u.LUA_MULTRET,c=u.LUA_OK,f=u.LUA_REGISTRYINDEX,_=u.LUA_RIDX_MAINTHREAD,p=u.LUA_TBOOLEAN,v=u.LUA_TFUNCTION,h=u.LUA_TLIGHTUSERDATA,L=u.LUA_TNIL,d=u.LUA_TNONE,A=u.LUA_TNUMBER,g=u.LUA_TSTRING,T=u.LUA_TTABLE,x=u.LUA_TTHREAD,b=u.LUA_TUSERDATA,k=u.lua_atnativeerror,O=u.lua_call,E=u.lua_getfield,m=u.lua_gettable,U=u.lua_gettop,N=u.lua_isnil,R=u.lua_isproxy,y=u.lua_newuserdata,S=u.lua_pcall,w=u.lua_pop,I=u.lua_pushboolean,M=u.lua_pushcfunction,P=u.lua_pushinteger,C=u.lua_pushlightuserdata,D=u.lua_pushliteral,V=u.lua_pushnil,B=u.lua_pushnumber,G=u.lua_pushstring,K=u.lua_pushvalue,F=u.lua_rawgeti,j=u.lua_rawgetp,H=u.lua_rawsetp,X=u.lua_rotate,z=u.lua_setfield,Y=u.lua_settable,J=u.lua_settop,Z=u.lua_toboolean,q=u.lua_tojsstring,W=u.lua_tonumber,Q=u.lua_toproxy,$=u.lua_tothread,tt=u.lua_touserdata,et=u.lua_type,rt=s.luaL_argerror,nt=s.luaL_checkany,at=s.luaL_checkoption,ut=s.luaL_checkstack,st=s.luaL_checkudata,ot=s.luaL_error,lt=s.luaL_getmetafield,it=s.luaL_newlib,ct=s.luaL_newmetatable,ft=s.luaL_requiref,_t=s.luaL_setfuncs,pt=s.luaL_setmetatable,vt=s.luaL_testudata,ht=s.luaL_tolstring,Lt=o.luaopen_base;var dt,At,gt,Tt="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:(0,eval)("this");if("undefined"!=typeof Reflect)dt=Reflect.apply,At=Reflect.construct,gt=Reflect.deleteProperty;else{var xt=Function.apply,bt=Function.bind;dt=function(t,e,r){return xt.call(t,e,r)},At=function(t,e){switch(e.length){case 0:return new t;case 1:return new t(e[0]);case 2:return new t(e[0],e[1]);case 3:return new t(e[0],e[1],e[2]);case 4:return new t(e[0],e[1],e[2],e[3])}var r=[null];return r.push.apply(r,e),new(bt.apply(t,r))},gt=Function("t","k","delete t[k]")}var kt=String.prototype.concat.bind(""),Ot=function(t){return"object"===n(t)?null!==t:"function"==typeof t},Et=l("js object"),mt=function(t,e){var r=vt(t,e,Et);return r?r.data:void 0},Ut=function(t,e){return st(t,e,Et).data},Nt=function(t,e){y(t).data=e,pt(t,Et)},Rt=function(t){F(t,f,_);var e=$(t,-1);return w(t,1),e},yt=new WeakMap,St=function(t,e){switch(n(e)){case"undefined":V(t);break;case"number":B(t,e);break;case"string":G(t,l(e));break;case"boolean":I(t,e);break;case"symbol":C(t,e);break;case"function":if(R(e,t)){e(t);break}case"object":if(null===e){if(j(t,f,null)!==b)throw Error("js library not loaded into lua_State");break}default:var r=yt.get(Rt(t));if(!r)throw Error("js library not loaded into lua_State");var a=r.get(e);a?a(t):(Nt(t,e),a=Q(t,-1),r.set(e,a))}},wt=function(t){var e=tt(t,1);return St(t,e),1},It=function(t,e){switch(et(t,e)){case d:case L:return;case p:return Z(t,e);case h:return tt(t,e);case A:return W(t,e);case g:return q(t,e);case b:var r=mt(t,e);if(void 0!==r)return r;case T:case v:case x:default:return jt(t,Q(t,e))}},Mt=function(t,e){var r=S(t,e,1,0),n=It(t,-1);switch(w(t,1),r){case c:return n;default:throw n}},Pt=function(t,e,r,n,a){if(!Ot(n))throw new TypeError("`args` argument must be an object");var u=+n.length;u>=0||(u=0),ut(t,2+u,null);var s=U(t);e(t),St(t,r);for(var o=0;ovoid 0;"),qt=function(t,e,r){var n,a=Rt(t);switch(r){case"function":n=function(){var t=function(){}.bind();return delete t.length,delete t.name,t}();break;case"arrow_function":n=function(){var t=Zt();return delete t.length,delete t.name,t}();break;case"object":n={};break;default:throw TypeError("invalid type to createproxy")}return n[Yt]=e,n[zt]=a,new Proxy(n,Jt)},Wt=["function","arrow_function","object"],Qt=Wt.map(function(t){return l(t)});Ht.createproxy=function(t){nt(t,1);var e=Wt[at(t,2,Qt[0],Qt)],r=qt(t,Q(t,1),e);return St(t,r),1}}var $t={__index:function(t){var e=Ut(t,1),r=It(t,2);return St(t,e[r]),1},__newindex:function(t){var e=Ut(t,1),r=It(t,2),n=It(t,3);return void 0===n?gt(e,r):e[r]=n,0},__tostring:function(t){var e=Ut(t,1),r=kt(e);return G(t,l(r)),1},__call:function(t){var e,r=Ut(t,1),n=U(t)-1,a=new Array(Math.max(0,n-1));if(n>0&&(e=It(t,2),n-- >0))for(var u=0;u=this.keys.length)){var e=this.keys[this.index++];return[e,this.object[e]]}},n={object:u,keys:Object.keys(u),index:0};else{var s=dt(e,u,[]);void 0===s&&ot(t,l("bad '__pairs' result (object with keys 'iter', 'state', 'first' expected)")),void 0===(r=s.iter)&&ot(t,l("bad '__pairs' result (object.iter is missing)")),n=s.state,a=s.first}return M(t,function(){var e=It(t,1),n=It(t,2),a=dt(r,e,[n]);if(void 0===a)return 0;Array.isArray(a)||ot(t,l("bad iterator result (Array or undefined expected)")),ut(t,a.length,null);for(var u=0;u0){var n=r.funcOff+e;return I(t,e<=r.top-(r.funcOff+1),"unacceptable index"),n>=t.top?V.luaO_nilobject:t.stack[n]}return e>c?(I(t,0!==e&&-e<=t.top,"invalid index"),t.stack[t.top+e]):e===c?t.l_G.l_registry:(I(t,(e=c-e)<=D.MAXUPVAL+1,"upvalue index too large"),r.func.ttislcf()?V.luaO_nilobject:e<=r.func.value.nupvalues?r.func.value.upvalue[e-1]:V.luaO_nilobject)},nt=function(t,e){var r=t.ci;if(e>0){var n=r.funcOff+e;return I(t,e<=r.top-(r.funcOff+1),"unacceptable index"),n>=t.top?null:n}if(e>c)return I(t,0!==e&&-e<=t.top,"invalid index"),t.top+e;throw Error("attempt to use pseudo-index")},at=function(t,e){var r,n=t.ci.funcOff;e>=0?(I(t,e<=t.stack_last-(n+1),"new top too large"),r=n+1+e):(I(t,-(e+1)<=t.top-(n+1),"invalid new top"),r=t.top+e+1),P.adjust_top(t,r)},ut=function(t,e){at(t,-e-1)},st=function(t,e,r){for(;ec,"index not in the stack"),I(t,(r>=0?r:-r)<=n-a+1,"invalid 'n'");var s=r>=0?n-r:a-r-1;st(t,a,s),st(t,s+1,t.top-1),st(t,a,t.top-1)},lt=function(t,e,r){var n=rt(t,e);rt(t,r).setfrom(n)},it=function(t,e,r){if($("function"==typeof e),tt(r),0===r)t.stack[t.top]=new Z(A,e);else{Q(t,r),I(t,r<=D.MAXUPVAL,"upvalue index too large");for(var n=new q(t,e,r),a=0;a0&&--t.top,t.stack[t.top].setclCvalue(n)}W(t)},ct=it,ft=function(t,e){it(t,e,0)},_t=ft,pt=function(t,e,r){var n=F(t,S(r));Q(t,1),V.pushsvalue2s(t,n),I(t,t.top<=t.ci.top,"stack overflow"),z.settable(t,e,t.stack[t.top-1],t.stack[t.top-2]),delete t.stack[--t.top],delete t.stack[--t.top]},vt=function(t,e){pt(t,Y.luaH_getint(t.l_G.l_registry.value,f),e)},ht=function(t,e,r){var n=F(t,S(r));return V.pushsvalue2s(t,n),I(t,t.top<=t.ci.top,"stack overflow"),z.luaV_gettable(t,e,t.stack[t.top-1],t.top-1),t.stack[t.top-1].ttnov()},Lt=function(t,e,r){var n=rt(t,e);return tt(r),I(t,n.ttistable(),"table expected"),V.pushobj2s(t,Y.luaH_getint(n.value,r)),I(t,t.top<=t.ci.top,"stack overflow"),t.stack[t.top-1].ttnov()},dt=function(t,e,r){var n=new V.TValue(U,Y.luaH_new(t));t.stack[t.top]=n,W(t)},At=function(t,e,r){switch(tt(r),e.ttype()){case L:var n=e.value;return 1<=r&&r<=n.nupvalues?{name:w("",!0),val:n.upvalue[r-1]}:null;case g:var a=e.value,u=a.p;if(!(1<=r&&r<=u.upvalues.length))return null;var s=u.upvalues[r-1].name;return{name:s?s.getstr():w("(*no name)",!0),val:a.upvals[r-1]};default:return null}},gt=function(t,e){var r=rt(t,e);if(!r.ttisstring()){if(!z.cvt2str(r))return null;V.luaO_tostring(t,r)}return r.svalue()},Tt=gt,xt=function(t,e){return z.tointeger(rt(t,e))},bt=function(t,e){return z.tonumber(rt(t,e))},kt=new WeakMap,Ot=function(t,e){P.luaD_callnoyield(t,e.funcOff,e.nresults)},Et=function(t,e){var r=rt(t,e);return et(r)?r.ttnov():k},mt=w("?"),Ut=function(t,e,r){I(t,r===a||t.ci.top-t.top>=r-e,"results from function overflow current stack size")},Nt=function(t,e,r,n,u){I(t,null===u||!(t.ci.callstatus&B.CIST_LUA),"cannot use continuations inside hooks"),Q(t,e+1),I(t,t.status===y,"cannot do calls on non-normal thread"),Ut(t,e,r);var s=t.top-(e+1);null!==u&&0===t.nny?(t.ci.c_k=u,t.ci.c_ctx=n,P.luaD_call(t,s,r)):P.luaD_callnoyield(t,s,r),r===a&&t.ci.top0){var c={funcOff:i,nresults:r};o=P.luaD_pcall(t,Ot,c,i,l)}else{var f=t.ci;f.c_k=s,f.c_ctx=u,f.extra=i,f.c_old_errfunc=t.errfunc,t.errfunc=l,f.callstatus&=~B.CIST_OAH|t.allowhook,f.callstatus|=B.CIST_YPCALL,P.luaD_call(t,i,r),f.callstatus&=~B.CIST_YPCALL,t.errfunc=f.c_old_errfunc,o=y}return r===a&&t.ci.top0||e<=c?e:t.top-t.ci.funcOff+e},t.exports.lua_arith=function(t,e){e!==i&&e!==u?Q(t,2):(Q(t,1),V.pushobj2s(t,t.stack[t.top-1]),I(t,t.top<=t.ci.top,"stack overflow")),V.luaO_arith(t,e,t.stack[t.top-2],t.stack[t.top-1],t.stack[t.top-2]),delete t.stack[--t.top]},t.exports.lua_atpanic=function(t,e){var r=t.l_G.panic;return t.l_G.panic=e,r},t.exports.lua_atnativeerror=function(t,e){var r=t.l_G.atnativeerror;return t.l_G.atnativeerror=e,r},t.exports.lua_call=function(t,e,r){Nt(t,e,r,0,null)},t.exports.lua_callk=Nt,t.exports.lua_checkstack=function(t,e){var r,n=t.ci;I(t,e>=0,"negative 'n'"),t.stack_last-t.top>e?r=!0:t.top+B.EXTRA_STACK>X-e?r=!1:(P.luaD_growstack(t,e),r=!0);return r&&n.top=2?z.luaV_concat(t,e):0===e&&(V.pushsvalue2s(t,K(t,w("",!0))),I(t,t.top<=t.ci.top,"stack overflow"))},t.exports.lua_copy=lt,t.exports.lua_createtable=dt,t.exports.lua_dump=function(t,e,r,n){Q(t,1);var a=t.stack[t.top-1];return a.ttisLclosure()?C(t,a.value.p,e,r,n):1},t.exports.lua_error=function(t){Q(t,1),M.luaG_errormsg(t)},t.exports.lua_gc=function(){},t.exports.lua_getallocf=function(){return console.warn("lua_getallocf is not available"),0},t.exports.lua_getextraspace=function(){return console.warn("lua_getextraspace is not available"),0},t.exports.lua_getfield=function(t,e,r){return ht(t,rt(t,e),r)},t.exports.lua_getglobal=function(t,e){return ht(t,Y.luaH_getint(t.l_G.l_registry.value,f),e)},t.exports.lua_geti=function(t,e,r){var n=rt(t,e);return tt(r),t.stack[t.top]=new Z(E,r),W(t),z.luaV_gettable(t,n,t.stack[t.top-1],t.top-1),t.stack[t.top-1].ttnov()},t.exports.lua_getmetatable=function(t,e){var r,n=rt(t,e),a=!1;switch(n.ttnov()){case U:case R:r=n.value.metatable;break;default:r=t.l_G.mt[n.ttnov()]}return null!==r&&void 0!==r&&(t.stack[t.top]=new Z(U,r),W(t),a=!0),a},t.exports.lua_gettable=function(t,e){var r=rt(t,e);return z.luaV_gettable(t,r,t.stack[t.top-1],t.top-1),t.stack[t.top-1].ttnov()},t.exports.lua_gettop=function(t){return t.top-(t.ci.funcOff+1)},t.exports.lua_getupvalue=function(t,e,r){var n=At(0,rt(t,e),r);if(n){var a=n.name,u=n.val;return V.pushobj2s(t,u),I(t,t.top<=t.ci.top,"stack overflow"),a}return null},t.exports.lua_getuservalue=function(t,e){var r=rt(t,e);I(t,r.ttisfulluserdata(),"full userdata expected");var n=r.value.uservalue;return t.stack[t.top]=new Z(n.type,n.value),W(t),t.stack[t.top-1].ttnov()},t.exports.lua_insert=function(t,e){ot(t,e,1)},t.exports.lua_isboolean=function(t,e){return Et(t,e)===h},t.exports.lua_iscfunction=function(t,e){var r=rt(t,e);return r.ttislcf(r)||r.ttisCclosure()},t.exports.lua_isfunction=function(t,e){return Et(t,e)===d},t.exports.lua_isinteger=function(t,e){return rt(t,e).ttisinteger()},t.exports.lua_islightuserdata=function(t,e){return Et(t,e)===T},t.exports.lua_isnil=function(t,e){return Et(t,e)===b},t.exports.lua_isnone=function(t,e){return Et(t,e)===k},t.exports.lua_isnoneornil=function(t,e){return Et(t,e)<=0},t.exports.lua_isnumber=function(t,e){return!1!==z.tonumber(rt(t,e))},t.exports.lua_isproxy=function(t,e){var r=kt.get(t);return!!r&&(null===e||e.l_G===r)},t.exports.lua_isstring=function(t,e){var r=rt(t,e);return r.ttisstring()||z.cvt2str(r)},t.exports.lua_istable=function(t,e){return rt(t,e).ttistable()},t.exports.lua_isthread=function(t,e){return Et(t,e)===N},t.exports.lua_isuserdata=function(t,e){var r=rt(t,e);return r.ttisfulluserdata(r)||r.ttislightuserdata()},t.exports.lua_len=function(t,e){var r=rt(t,e),n=new Z;z.luaV_objlen(t,n,r),t.stack[t.top]=n,W(t)},t.exports.lua_load=function(t,e,r,n,a){n=n?S(n):mt,null!==a&&(a=S(a));var u=new J(t,e,r),s=P.luaD_protectedparser(t,u,n,a);if(s===y){var o=t.stack[t.top-1].value;if(o.nupvalues>=1){var l=Y.luaH_getint(t.l_G.l_registry.value,f);o.upvals[0].setfrom(l)}}return s},t.exports.lua_newtable=function(t){dt(t)},t.exports.lua_newuserdata=function(t,e){var r=function(t,e){return new V.Udata(t,e)}(t,e);return t.stack[t.top]=new V.TValue(R,r),W(t),r.data},t.exports.lua_next=function(t,e){var r=rt(t,e);return I(t,r.ttistable(),"table expected"),t.stack[t.top]=new Z,Y.luaH_next(t,r.value,t.top-1)?(W(t),1):(delete t.stack[t.top],delete t.stack[--t.top],0)},t.exports.lua_pcall=function(t,e,r,n){return Rt(t,e,r,n,0,null)},t.exports.lua_pcallk=Rt,t.exports.lua_pop=ut,t.exports.lua_pushboolean=function(t,e){t.stack[t.top]=new Z(h,!!e),W(t)},t.exports.lua_pushcclosure=it,t.exports.lua_pushcfunction=ft,t.exports.lua_pushfstring=function(t,e){e=S(e);for(var r=arguments.length,n=new Array(r>2?r-2:0),a=2;a=r,"invalid length to lua_pushlstring"),n=F(t,e.subarray(0,r))),V.pushsvalue2s(t,n),I(t,t.top<=t.ci.top,"stack overflow"),n.value},t.exports.lua_pushnil=function(t){t.stack[t.top]=new Z(b,null),W(t)},t.exports.lua_pushnumber=function(t,e){$("number"==typeof e),t.stack[t.top]=new Z(O,e),W(t)},t.exports.lua_pushstring=function(t,e){if(void 0===e||null===e)t.stack[t.top]=new Z(b,null),t.top++;else{var r=F(t,S(e));V.pushsvalue2s(t,r),e=r.getstr()}return I(t,t.top<=t.ci.top,"stack overflow"),e},t.exports.lua_pushthread=function(t){return t.stack[t.top]=new Z(N,t),W(t),t.l_G.mainthread===t},t.exports.lua_pushvalue=function(t,e){V.pushobj2s(t,rt(t,e)),I(t,t.top<=t.ci.top,"stack overflow")},t.exports.lua_pushvfstring=function(t,e,r){return e=S(e),V.luaO_pushvfstring(t,e,r)},t.exports.lua_rawequal=function(t,e,r){var n=rt(t,e),a=rt(t,r);return et(n)&&et(a)?z.luaV_equalobj(null,n,a):0},t.exports.lua_rawget=function(t,e){var r=rt(t,e);return I(t,r.ttistable(r),"table expected"),V.setobj2s(t,t.top-1,Y.luaH_get(t,r.value,t.stack[t.top-1])),t.stack[t.top-1].ttnov()},t.exports.lua_rawgeti=Lt,t.exports.lua_rawgetp=function(t,e,r){var n=rt(t,e);I(t,n.ttistable(),"table expected");var a=new Z(T,r);return V.pushobj2s(t,Y.luaH_get(t,n.value,a)),I(t,t.top<=t.ci.top,"stack overflow"),t.stack[t.top-1].ttnov()},t.exports.lua_rawlen=function(t,e){var r=rt(t,e);switch(r.ttype()){case m:case x:return r.vslen();case R:return r.value.len;case U:return Y.luaH_getn(r.value);default:return 0}},t.exports.lua_rawset=function(t,e){Q(t,2);var r=rt(t,e);I(t,r.ttistable(),"table expected");var n=t.stack[t.top-2],a=t.stack[t.top-1];Y.luaH_setfrom(t,r.value,n,a),Y.invalidateTMcache(r.value),delete t.stack[--t.top],delete t.stack[--t.top]},t.exports.lua_rawseti=function(t,e,r){tt(r),Q(t,1);var n=rt(t,e);I(t,n.ttistable(),"table expected"),Y.luaH_setint(n.value,r,t.stack[t.top-1]),delete t.stack[--t.top]},t.exports.lua_rawsetp=function(t,e,r){Q(t,1);var n=rt(t,e);I(t,n.ttistable(),"table expected");var a=new Z(T,r),u=t.stack[t.top-1];Y.luaH_setfrom(t,n.value,a,u),delete t.stack[--t.top]},t.exports.lua_register=function(t,e,r){ft(t,r),vt(t,e)},t.exports.lua_remove=function(t,e){ot(t,e,-1),ut(t,1)},t.exports.lua_replace=function(t,e){lt(t,-1,e),ut(t,1)},t.exports.lua_rotate=ot,t.exports.lua_setallocf=function(){return console.warn("lua_setallocf is not available"),0},t.exports.lua_setfield=function(t,e,r){pt(t,rt(t,e),r)},t.exports.lua_setglobal=vt,t.exports.lua_seti=function(t,e,r){tt(r),Q(t,1);var n=rt(t,e);t.stack[t.top]=new Z(E,r),W(t),z.settable(t,n,t.stack[t.top-1],t.stack[t.top-2]),delete t.stack[--t.top],delete t.stack[--t.top]},t.exports.lua_setmetatable=function(t,e){var r;Q(t,1);var n=rt(t,e);switch(t.stack[t.top-1].ttisnil()?r=null:(I(t,t.stack[t.top-1].ttistable(),"table expected"),r=t.stack[t.top-1].value),n.ttnov()){case R:case U:n.value.metatable=r;break;default:t.l_G.mt[n.ttnov()]=r}return delete t.stack[--t.top],!0},t.exports.lua_settable=function(t,e){Q(t,2);var r=rt(t,e);z.settable(t,r,t.stack[t.top-2],t.stack[t.top-1]),delete t.stack[--t.top],delete t.stack[--t.top]},t.exports.lua_settop=at,t.exports.lua_setupvalue=function(t,e,r){var n=rt(t,e);Q(t,1);var a=At(0,n,r);if(a){var u=a.name;return a.val.setfrom(t.stack[t.top-1]),delete t.stack[--t.top],u}return null},t.exports.lua_setuservalue=function(t,e){Q(t,1);var r=rt(t,e);I(t,r.ttisfulluserdata(),"full userdata expected"),r.value.uservalue.setfrom(t.stack[t.top-1]),delete t.stack[--t.top]},t.exports.lua_status=function(t){return t.status},t.exports.lua_stringtonumber=function(t,e){var r=new Z,n=V.luaO_str2num(e,r);return 0!==n&&(t.stack[t.top]=r,W(t)),n},t.exports.lua_toboolean=function(t,e){return!rt(t,e).l_isfalse()},t.exports.lua_tocfunction=function(t,e){var r=rt(t,e);return r.ttislcf()||r.ttisCclosure()?r.value:null},t.exports.lua_todataview=function(t,e){var r=gt(t,e);return new DataView(r.buffer,r.byteOffset,r.byteLength)},t.exports.lua_tointeger=function(t,e){var r=xt(t,e);return!1===r?0:r},t.exports.lua_tointegerx=xt,t.exports.lua_tojsstring=function(t,e){var r=rt(t,e);if(!r.ttisstring()){if(!z.cvt2str(r))return null;V.luaO_tostring(t,r)}return r.jsstring()},t.exports.lua_tolstring=gt,t.exports.lua_tonumber=function(t,e){var r=bt(t,e);return!1===r?0:r},t.exports.lua_tonumberx=bt,t.exports.lua_topointer=function(t,e){var r=rt(t,e);switch(r.ttype()){case U:case g:case L:case A:case N:case R:case T:return r.value;default:return null}},t.exports.lua_toproxy=function(t,e){var r=rt(t,e);return function(t,e,r){var n=function(n){I(n,n instanceof B.lua_State&&t===n.l_G,"must be from same global state"),n.stack[n.top]=new Z(e,r),W(n)};return kt.set(n,t),n}(t.l_G,r.type,r.value)},t.exports.lua_tostring=Tt,t.exports.lua_tothread=function(t,e){var r=rt(t,e);return r.ttisthread()?r.value:null},t.exports.lua_touserdata=function(t,e){var r=rt(t,e);switch(r.ttnov()){case R:return r.value.data;case T:return r.value;default:return null}},t.exports.lua_type=Et,t.exports.lua_typename=function(t,e){return I(t,k<=e&&e0&&r<=u.nupvalues,"invalid upvalue index"),u.upvalue[r-1];default:return I(t,!1,"closure expected"),null}},t.exports.lua_upvaluejoin=function(t,e,r,n,a){var u=yt(t,e,r),s=yt(t,n,a),o=s.f.upvals[s.i];u.f.upvals[u.i]=o},t.exports.lua_version=function(t){return null===t?_:t.l_G.version},t.exports.lua_xmove=function(t,e,r){if(t!==e){Q(t,r),I(t,t.l_G===e.l_G,"moving among independent states"),I(t,e.ci.top-e.top>=r,"stack overflow"),t.top-=r;for(var n=0;n0?this.buffer[this.off++]:o(this)}}]),t}(),o=function(t){var e=t.reader(t.L,t.data);if(null===e)return-1;u(e instanceof Uint8Array,"Should only load binary of array of bytes");var r=e.length;return 0===r?-1:(t.buffer=e,t.off=0,t.n=r-1,t.buffer[t.off++])};t.exports.EOZ=-1,t.exports.luaZ_buffer=function(t){return t.buffer.subarray(0,t.n)},t.exports.luaZ_buffremove=function(t,e){t.n-=e},t.exports.luaZ_fill=o,t.exports.luaZ_read=function(t,e,r,n){for(;n;){if(0===t.n){if(-1===o(t))return n;t.n++,t.off--}for(var a=n<=t.n?n:t.n,u=0;u=","<=","~=","<<",">>","::","","","","",""].map(function(t,e){return i(t)}),V=function t(){n(this,t),this.r=NaN,this.i=NaN,this.ts=null},B=function t(){n(this,t),this.token=NaN,this.seminfo=new V},G=function(t,e){var r=t.buff;if(r.n+1>r.buffer.length){r.buffer.length>=_/2&&W(t,i("lexical element too long",!0),0);var n=2*r.buffer.length;M(t.L,r,n)}r.buffer[r.n++]=e<0?255+e+1:e},K=function(t,e){if(e<257)return b.luaO_pushfstring(t.L,i("'%c'",!0),e);var r=D[e-257];return e<289?b.luaO_pushfstring(t.L,i("'%s'",!0),r):r},F=function(t){return 10===t.current||13===t.current},j=function(t){t.current=t.z.zgetc()},H=function(t){G(t,t.current),j(t)},X=new b.TValue(s,!0),z=function(t,e){var r=t.L,n=U(r,e),a=t.h.strong.get(m(n));if(a)n=a.key.tsvalue();else{var u=new b.TValue(o,n);N.luaH_setfrom(r,t.h,u,X)}return n},Y=function(t){var e=t.current;p(F(t)),j(t),F(t)&&t.current!==e&&j(t),++t.linenumber>=_&&W(t,i("chunk has too many lines",!0),0)},J=function(t,e){return t.current===e&&(j(t),!0)},Z=function(t,e){return(t.current===e[0].charCodeAt(0)||t.current===e[1].charCodeAt(0))&&(H(t),!0)},q=function(t,e){var r="Ee",n=t.current;for(p(d(t.current)),H(t),48===n&&Z(t,"xX")&&(r="Pp");;)if(Z(t,r)&&Z(t,"-+"),x(t.current))H(t);else{if(46!==t.current)break;H(t)}var a=new b.TValue;return 0===b.luaO_str2num(S(t.buff),a)&&W(t,i("malformed number",!0),290),a.ttisinteger()?(e.i=a.value,291):(p(a.ttisfloat()),e.r=a.value,290)},W=function(t,e,r){e=v.luaG_addinfo(t.L,e,t.source,t.linenumber),r&&b.luaO_pushfstring(t.L,i("%s near %s"),e,function(t,e){switch(e){case 292:case 293:case 290:case 291:return b.luaO_pushfstring(t.L,i("'%s'",!0),S(t.buff));default:return K(t,e)}}(t,r)),h.luaD_throw(t.L,l)},Q=function(t){var e=0,r=t.current;for(p(91===r||93===r),H(t);61===t.current;)H(t),e++;return t.current===r?e:-e-1},$=function(t,e,r){var n=t.linenumber;H(t),F(t)&&Y(t);for(var a=!1;!a;)switch(t.current){case y:var u="unfinished long ".concat(e?"string":"comment"," (starting at line ").concat(n,")");W(t,i(u),289);break;case 93:Q(t)===r&&(H(t),a=!0);break;case 10:case 13:G(t,10),Y(t),e||I(t.buff);break;default:e?H(t):j(t)}e&&(e.ts=z(t,t.buff.buffer.subarray(2+r,t.buff.n-(2+r))))},tt=function(t,e,r){e||(t.current!==y&&H(t),W(t,r,293))},et=function(t){return H(t),tt(t,x(t.current),i("hexadecimal digit expected",!0)),b.luaO_hexavalue(t.current)},rt=function(t){var e=et(t);return e=(e<<4)+et(t),w(t.buff,2),e},nt=function(t){for(var e=new Uint8Array(b.UTF8BUFFSZ),r=b.luaO_utf8esc(e,function(t){var e=4;H(t),tt(t,123===t.current,i("missing '{'",!0));var r=et(t);for(H(t);x(t.current);)e++,r=(r<<4)+b.luaO_hexavalue(t.current),tt(t,r<=1114111,i("UTF-8 value too large",!0)),H(t);return tt(t,125===t.current,i("missing '}'",!0)),j(t),w(t.buff,e),r}(t));r>0;r--)G(t,e[b.UTF8BUFFSZ-r])},at=function(t){var e,r=0;for(e=0;e<3&&d(t.current);e++)r=10*r+t.current-48,H(t);return tt(t,r<=255,i("decimal escape too large",!0)),w(t.buff,e),r},ut=function(t,e,r){for(H(t);t.current!==e;)switch(t.current){case y:W(t,i("unfinished string",!0),289);break;case 10:case 13:W(t,i("unfinished string",!0),293);break;case 92:H(t);var n=void 0,a=void 0;switch(t.current){case 97:a=7,n="read_save";break;case 98:a=8,n="read_save";break;case 102:a=12,n="read_save";break;case 110:a=10,n="read_save";break;case 114:a=13,n="read_save";break;case 116:a=9,n="read_save";break;case 118:a=11,n="read_save";break;case 120:a=rt(t),n="read_save";break;case 117:nt(t),n="no_save";break;case 10:case 13:Y(t),a=10,n="only_save";break;case 92:case 34:case 39:a=t.current,n="read_save";break;case y:n="no_save";break;case 122:for(w(t.buff,1),j(t);T(t.current);)F(t)?Y(t):j(t);n="no_save";break;default:tt(t,d(t.current),i("invalid escape sequence",!0)),a=at(t),n="only_save"}"read_save"===n&&j(t),"read_save"!==n&&"only_save"!==n||(w(t.buff,1),G(t,a));break;default:H(t)}H(t),r.ts=z(t,t.buff.buffer.subarray(1,t.buff.n-1))},st=Object.create(null);D.forEach(function(t,e){return st[E(t)]=e});var ot=function(t,e){for(I(t.buff);;)switch(p("number"==typeof t.current),t.current){case 10:case 13:Y(t);break;case 32:case 12:case 9:case 11:j(t);break;case 45:if(j(t),45!==t.current)return 45;if(j(t),91===t.current){var r=Q(t);if(I(t.buff),r>=0){$(t,null,r),I(t.buff);break}}for(;!F(t)&&t.current!==y;)j(t);break;case 91:var n=Q(t);return n>=0?($(t,e,n),293):(-1!==n&&W(t,i("invalid long string delimiter",!0),293),91);case 61:return j(t),J(t,61)?282:61;case 60:return j(t),J(t,61)?284:J(t,60)?286:60;case 62:return j(t),J(t,61)?283:J(t,62)?287:62;case 47:return j(t),J(t,47)?279:47;case 126:return j(t),J(t,61)?285:126;case 58:return j(t),J(t,58)?288:58;case 34:case 39:return ut(t,t.current,e),293;case 46:return H(t),J(t,46)?J(t,46)?281:280:d(t.current)?q(t,e):46;case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return q(t,e);case y:return 289;default:if(g(t.current)){do{H(t)}while(A(t.current));var a=z(t,S(t.buff));e.ts=a;var u=st[m(a)];return void 0!==u&&u<=22?u+257:292}var s=t.current;return j(t),s}};t.exports.FIRST_RESERVED=257,t.exports.LUA_ENV=P,t.exports.LexState=function t(){n(this,t),this.current=NaN,this.linenumber=NaN,this.lastline=NaN,this.t=new B,this.lookahead=new B,this.fs=null,this.L=null,this.z=null,this.buff=null,this.h=null,this.dyd=null,this.source=null,this.envn=null},t.exports.RESERVED=C,t.exports.isreserved=function(t){var e=st[m(t)];return void 0!==e&&e<=22},t.exports.luaX_lookahead=function(t){return p(289===t.lookahead.token),t.lookahead.token=ot(t,t.lookahead.seminfo),t.lookahead.token},t.exports.luaX_newstring=z,t.exports.luaX_next=function(t){t.lastline=t.linenumber,289!==t.lookahead.token?(t.t.token=t.lookahead.token,t.t.seminfo.i=t.lookahead.seminfo.i,t.t.seminfo.r=t.lookahead.seminfo.r,t.t.seminfo.ts=t.lookahead.seminfo.ts,t.lookahead.token=289):t.t.token=ot(t,t.t.seminfo)},t.exports.luaX_setinput=function(t,e,r,n,a){e.t={token:0,seminfo:new V},e.L=t,e.current=a,e.lookahead={token:289,seminfo:new V},e.z=r,e.fs=null,e.linenumber=1,e.lastline=1,e.source=n,e.envn=O(t,P),M(t,e.buff,f)},t.exports.luaX_syntaxerror=function(t,e){W(t,e,t.t.token)},t.exports.luaX_token2str=K,t.exports.luaX_tokens=D},function(t,e,r){"use strict";var n=(0,r(1).luastring_of)(0,0,0,0,0,0,0,0,0,0,8,8,8,8,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,22,22,22,22,22,22,22,22,22,22,4,4,4,4,4,4,4,21,21,21,21,21,21,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,5,4,21,21,21,21,21,21,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);t.exports.lisdigit=function(t){return 0!=(2&n[t+1])},t.exports.lislalnum=function(t){return 0!=(3&n[t+1])},t.exports.lislalpha=function(t){return 0!=(1&n[t+1])},t.exports.lisprint=function(t){return 0!=(4&n[t+1])},t.exports.lisspace=function(t){return 0!=(8&n[t+1])},t.exports.lisxdigit=function(t){return 0!=(16&n[t+1])}},function(t,e,r){"use strict";function n(t,e){for(var r=0;rr&&function(t,e,r){var n=t.ls.L,a=t.f.linedefined,u=0===a?o("main function",!0):Rt.luaO_pushfstring(n,o("function at line %d",!0),a),s=Rt.luaO_pushfstring(n,o("too many %s (limit is %d) in %s",!0),r,e,u);Ot.luaX_syntaxerror(t.ls,s)}(t,r,n)},fe=function(t,e){return t.t.token===e&&(Ot.luaX_next(t),!0)},_e=function(t,e){t.t.token!==e&&ie(t,e)},pe=function(t,e){_e(t,e),Ot.luaX_next(t)},ve=function(t,e,r){e||Ot.luaX_syntaxerror(t,r)},he=function(t,e,r,n){fe(t,e)||(n===t.linenumber?ie(t,e):Ot.luaX_syntaxerror(t,Rt.luaO_pushfstring(t.L,o("%s expected (to close %s at line %d)"),Ot.luaX_token2str(t,e),Ot.luaX_token2str(t,r),n)))},Le=function(t){_e(t,te.TK_NAME);var e=t.t.seminfo.ts;return Ot.luaX_next(t),e},de=function(t,e,r){t.f=t.t=V,t.k=e,t.u.info=r},Ae=function(t,e,r){de(e,ae.VK,xt(t.fs,r))},ge=function(t,e){Ae(t,e,Le(t))},Te=function(t,e){var r=t.fs,n=t.dyd,u=function(t,e){var r=t.fs,n=r.f;return n.locvars[r.nlocvars]=new Rt.LocVar,n.locvars[r.nlocvars].varname=e,r.nlocvars++}(t,e);ce(r,n.actvar.n+1-r.firstlocal,200,o("local variables",!0)),n.actvar.arr[n.actvar.n]=new function t(){a(this,t),this.idx=NaN},n.actvar.arr[n.actvar.n].idx=u,n.actvar.n++},xe=function(t,e){Te(t,Ot.luaX_newstring(t,o(e,!0)))},be=function(t,e){var r=t.ls.dyd.actvar.arr[t.firstlocal+e].idx;return Nt(r=0;r--)if(re(e,be(t,r).varname))return r;return-1}(e,r);if(u>=0)de(n,ae.VLOCAL,u),a||function(t,e){for(var r=t.bl;r.nactvar>e;)r=r.previous;r.upval=1}(e,u);else{var s=function(t,e){for(var r=t.f.upvalues,n=0;n1&&pt(a,u-1);else if(n.k!==ae.VVOID&&q(a,n),u>0){var s=a.freereg;pt(a,u),ot(a,s,u)}r>e&&(t.fs.freereg-=r-e)},Ne=function(t){var e=t.L;++e.nCcalls,ce(t.fs,e.nCcalls,mt,o("JS levels",!0))},Re=function(t){return t.L.nCcalls--},ye=function(t,e,r){var n=t.fs,a=t.dyd.gt,u=a.arr[e];if(Nt(re(u.name,r.name)),u.nactvar at line %d jumps into the scope of local '%s'"),u.name.getstr(),u.line,s.getstr());le(t,l)}it(n,u.pc,r.pc);for(var i=e;is.nactvar&&(r.upval||n.label.n>r.firstlabel)&<(t.fs,a.pc,s.nactvar),ye(t,e,s),!0}return!1},we=function(t,e,r,n,u){var s=e.n;return e.arr[s]=new function t(){a(this,t),this.name=null,this.pc=NaN,this.line=NaN,this.nactvar=NaN},e.arr[s].name=r,e.arr[s].line=n,e.arr[s].nactvar=t.fs.nactvar,e.arr[s].pc=u,e.n=s+1,s},Ie=function(t,e){for(var r=t.dyd.gt,n=t.fs.bl.firstgoto;ne;)be(t,--t.nactvar).endpc=t.pc}(t,e.nactvar),Nt(e.nactvar===t.nactvar),t.freereg=t.nactvar,r.dyd.label.n=e.firstlabel,e.previous?function(t,e){for(var r=e.firstgoto,n=t.ls.dyd.gt;re.nactvar&&(e.upval&<(t,a.pc,e.nactvar),a.nactvar=e.nactvar),Se(t.ls,r)||r++}}(t,e):e.firstgoto at line %d not inside a loop":"no visible label '%s' for at line %d";r=Rt.luaO_pushfstring(t.L,o(r),e.name.getstr(),e.line),le(t,r)}(r,r.dyd.gt.arr[e.firstgoto])},De=function(t){var e=t.fs;vt(e,0,0),Ce(e),Nt(null===e.bl),t.fs=e.prev},Ve=function(t,e){switch(t.t.token){case te.TK_ELSE:case te.TK_ELSEIF:case te.TK_END:case te.TK_EOS:return!0;case te.TK_UNTIL:return e;default:return!1}},Be=function(t){for(;!Ve(t,1);){if(t.t.token===te.TK_RETURN)return void fr(t);fr(t)}},Ge=function(t,e){var r=t.fs,n=new ue;Z(r,e),Ot.luaX_next(t),ge(t,n),rt(r,e,n)},Ke=function(t,e){Ot.luaX_next(t),$e(t,e),W(t.fs,e),pe(t,93)},Fe=function(t,e){var r=t.fs,n=t.fs.freereg,a=new ue,u=new ue;t.t.token===te.TK_NAME?(ce(r,e.nh,Ut,o("items in a constructor",!0)),ge(t,a)):Ke(t,a),e.nh++,pe(t,61);var s=Y(r,a);$e(t,u),K(r,Bt,e.t.u.info,s,Y(r,u)),r.freereg=n},je=function(t,e){e.v.k!==ae.VVOID&&(q(t,e.v),e.v.k=ae.VVOID,e.tostore===Ht&&(Lt(t,e.t.u.info,e.na,e.tostore),e.tostore=0))},He=function(t,e){$e(t,e.v),ce(t.fs,e.na,Ut,o("items in a constructor",!0)),e.na++,e.tostore++},Xe=function(t,e){switch(t.t.token){case te.TK_NAME:61!==Ot.luaX_lookahead(t)?He(t,e):Fe(t,e);break;case 91:Fe(t,e);break;default:He(t,e)}},ze=function(t,e){var r=t.fs,n=t.linenumber,u=K(r,Vt,0,0,0),o=new function t(){a(this,t),this.v=new ue,this.t=new ue,this.nh=NaN,this.na=NaN,this.tostore=NaN};o.na=o.nh=o.tostore=0,o.t=e,de(e,ae.VRELOCABLE,u),de(o.v,ae.VVOID,0),q(t.fs,e),pe(t,123);do{if(Nt(o.v.k===ae.VVOID||o.tostore>0),125===t.t.token)break;je(r,o),Xe(t,o)}while(fe(t,44)||fe(t,59));he(t,125,123,n),function(t,e){0!==e.tostore&&(ee(e.v.k)?(dt(t,e.v),Lt(t,e.t.u.info,e.na,s),e.na--):(e.v.k!==ae.VVOID&&q(t,e.v),Lt(t,e.t.u.info,e.na,e.tostore)))}(r,o),Xt(r.f.code[u],Rt.luaO_int2fb(o.na)),zt(r.f.code[u],Rt.luaO_int2fb(o.nh))},Ye=function(t,e,r,n){var a=new se,u=new ne;a.f=function(t){var e=t.L,r=new $t(e),n=t.fs;return n.f.p[n.np++]=r,r}(t),a.f.linedefined=n,Pe(t,a,u),pe(t,40),r&&(xe(t,"self"),ke(t,1)),function(t){var e=t.fs,r=e.f,n=0;if(r.is_vararg=!1,41!==t.t.token)do{switch(t.t.token){case te.TK_NAME:Te(t,Le(t)),n++;break;case te.TK_DOTS:Ot.luaX_next(t),r.is_vararg=!0;break;default:Ot.luaX_syntaxerror(t,o(" or '...' expected",!0))}}while(!r.is_vararg&&fe(t,44));ke(t,n),r.numparams=e.nactvar,pt(e,e.nactvar)}(t),pe(t,41),Be(t),a.f.lastlinedefined=t.linenumber,he(t,te.TK_END,te.TK_FUNCTION,n),function(t,e){var r=t.fs.prev;de(e,ae.VRELOCABLE,F(r,It,0,r.np-1)),q(r,e)}(t,e),De(t)},Je=function(t,e){var r=1;for($e(t,e);fe(t,44);)q(t.fs,e),$e(t,e),r++;return r},Ze=function(t,e,r){var n,a=t.fs,u=new ue;switch(t.t.token){case 40:Ot.luaX_next(t),41===t.t.token?u.k=ae.VVOID:(Je(t,u),dt(a,u)),he(t,41,40,r);break;case 123:ze(t,u);break;case te.TK_STRING:Ae(t,u,t.t.seminfo.ts),Ot.luaX_next(t);break;default:Ot.luaX_syntaxerror(t,o("function arguments expected",!0))}Nt(e.k===ae.VNONRELOC);var l=e.u.info;ee(u.k)?n=s:(u.k!==ae.VVOID&&q(a,u),n=a.freereg-(l+1)),de(e,ae.VCALL,K(a,wt,l,n+1,2)),Q(a,r),a.freereg=l+1},qe=function(t,e){var r=t.fs,n=t.linenumber;for(!function(t,e){switch(t.t.token){case 40:var r=t.linenumber;return Ot.luaX_next(t),$e(t,e),he(t,41,40,r),void z(t.fs,e);case te.TK_NAME:return void me(t,e);default:Ot.luaX_syntaxerror(t,o("unexpected symbol",!0))}}(t,e);;)switch(t.t.token){case 46:Ge(t,e);break;case 91:var a=new ue;Z(r,e),Ke(t,a),rt(r,e,a);break;case 58:var u=new ue;Ot.luaX_next(t),ge(t,u),ht(r,e,u),Ze(t,e,n);break;case 40:case te.TK_STRING:case 123:q(r,e),Ze(t,e,n);break;default:return}},We=[{left:10,right:10},{left:10,right:10},{left:11,right:11},{left:11,right:11},{left:14,right:13},{left:11,right:11},{left:11,right:11},{left:6,right:6},{left:4,right:4},{left:5,right:5},{left:7,right:7},{left:7,right:7},{left:9,right:8},{left:3,right:3},{left:3,right:3},{left:3,right:3},{left:3,right:3},{left:3,right:3},{left:3,right:3},{left:2,right:2},{left:1,right:1}],Qe=function t(e,r,n){Ne(e);var a=function(t){switch(t){case te.TK_NOT:return C;case 45:return P;case 126:return I;case 35:return M;default:return D}}(e.t.token);if(a!==D){var u=e.linenumber;Ot.luaX_next(e),t(e,r,12),_t(e.fs,a,r,u)}else!function(t,e){switch(t.t.token){case te.TK_FLT:de(e,ae.VKFLT,0),e.u.nval=t.t.seminfo.r;break;case te.TK_INT:de(e,ae.VKINT,0),e.u.ival=t.t.seminfo.i;break;case te.TK_STRING:Ae(t,e,t.t.seminfo.ts);break;case te.TK_NIL:de(e,ae.VNIL,0);break;case te.TK_TRUE:de(e,ae.VTRUE,0);break;case te.TK_FALSE:de(e,ae.VFALSE,0);break;case te.TK_DOTS:var r=t.fs;ve(t,r.f.is_vararg,o("cannot use '...' outside a vararg function",!0)),de(e,ae.VVARARG,K(r,jt,0,1,0));break;case 123:return void ze(t,e);case te.TK_FUNCTION:return Ot.luaX_next(t),void Ye(t,e,0,t.linenumber);default:return void qe(t,e)}Ot.luaX_next(t)}(e,r);for(var s=function(t){switch(t){case 43:return c;case 45:return S;case 42:return O;case 37:return k;case 94:return N;case 47:return L;case te.TK_IDIV:return T;case 38:return _;case 124:return p;case 126:return v;case te.TK_SHL:return R;case te.TK_SHR:return y;case te.TK_CONCAT:return h;case te.TK_NE:return E;case te.TK_EQ:return d;case 60:return b;case te.TK_LE:return x;case 62:return g;case te.TK_GE:return A;case te.TK_AND:return f;case te.TK_OR:return U;default:return m}}(e.t.token);s!==m&&We[s].left>n;){var l=new ue,i=e.linenumber;Ot.luaX_next(e),nt(e.fs,s,r);var w=t(e,l,We[s].right);ft(e.fs,s,r,l,i),s=w}return Re(e),s},$e=function(t,e){Qe(t,e,0)},tr=function(t){var e=t.fs,r=new ne;Me(e,r,0),Be(t),Ce(e)},er=function t(){a(this,t),this.prev=null,this.v=new ue},rr=function t(e,r,n){var a=new ue;if(ve(e,function(t){return ae.VLOCAL<=t&&t<=ae.VINDEXED}(r.v.k),o("syntax error",!0)),fe(e,44)){var u=new er;u.prev=r,qe(e,u.v),u.v.k!==ae.VINDEXED&&function(t,e,r){for(var n=t.fs,a=n.freereg,u=!1;e;e=e.prev)e.v.k===ae.VINDEXED&&(e.v.u.ind.vt===r.k&&e.v.u.ind.t===r.u.info&&(u=!0,e.v.u.ind.vt=ae.VLOCAL,e.v.u.ind.t=a),r.k===ae.VLOCAL&&e.v.u.ind.idx===r.u.info&&(u=!0,e.v.u.ind.idx=a));if(u){var s=r.k===ae.VLOCAL?Dt:Ct;K(n,s,a,r.u.info,0),pt(n,1)}}(e,r,u.v),ce(e.fs,n+e.L.nCcalls,mt,o("JS levels",!0)),t(e,u,n+1)}else{pe(e,61);var s=Je(e,a);if(s===n)return At(e.fs,a),void Tt(e.fs,r.v,a);Ue(e,n,s,a)}de(a,ae.VNONRELOC,e.fs.freereg-1),Tt(e.fs,r.v,a)},nr=function(t){var e=new ue;return $e(t,e),e.k===ae.VNIL&&(e.k=ae.VFALSE),et(t.fs,e),e.f},ar=function(t,e){var r,n=t.linenumber;fe(t,te.TK_GOTO)?r=Le(t):(Ot.luaX_next(t),r=Wt(t.L,"break"));var a=we(t,t.dyd.gt,r,n,e);Se(t,a)},ur=function(t,e,r){var n,a=t.fs,u=t.dyd.label;!function(t,e,r){for(var n=t.bl.firstlabel;n=t.fs.freereg&&t.fs.freereg>=t.fs.nactvar),t.fs.freereg=t.fs.nactvar,Re(t)};t.exports.Dyndata=function t(){a(this,t),this.actvar={arr:[],n:NaN,size:NaN},this.gt=new oe,this.label=new oe},t.exports.expkind=ae,t.exports.expdesc=ue,t.exports.luaY_parser=function(t,e,r,n,a,u){var s=new Ot.LexState,o=new se,l=kt.luaF_newLclosure(t,1);return bt.luaD_inctop(t),t.stack[t.top-1].setclLvalue(l),s.h=Qt.luaH_new(t),bt.luaD_inctop(t),t.stack[t.top-1].sethvalue(s.h),o.f=l.p=new $t(t),o.f.source=qt(t,a),s.buff=r,s.dyd=n,n.actvar.n=n.gt.n=n.label.n=0,Ot.luaX_setinput(t,s,e,o.f.source,u),function(t,e){var r=new ne,n=new ue;Pe(t,e,r),e.f.is_vararg=!0,de(n,ae.VLOCAL,0),Oe(e,t.envn,n),Ot.luaX_next(t),Be(t),_e(t,te.TK_EOS),De(t)}(s,o),Nt(!o.prev&&1===o.nups&&!s.fs),Nt(0===n.actvar.n&&0===n.gt.n&&0===n.label.n),delete t.stack[--t.top],l},t.exports.vkisinreg=function(t){return t===ae.VNONRELOC||t===ae.VLOCAL}},function(t,e,r){"use strict";var n,a,u=r(2),s=u.LUA_MULTRET,o=u.LUA_OK,l=u.LUA_TFUNCTION,i=u.LUA_TNIL,c=u.LUA_TNONE,f=u.LUA_TNUMBER,_=u.LUA_TSTRING,p=u.LUA_TTABLE,v=u.LUA_VERSION,h=u.LUA_YIELD,L=u.lua_call,d=u.lua_callk,A=u.lua_concat,g=u.lua_error,T=u.lua_getglobal,x=u.lua_geti,b=u.lua_getmetatable,k=u.lua_gettop,O=u.lua_insert,E=u.lua_isnil,m=u.lua_isnone,U=u.lua_isstring,N=u.lua_load,R=u.lua_next,y=u.lua_pcallk,S=u.lua_pop,w=u.lua_pushboolean,I=u.lua_pushcfunction,M=u.lua_pushglobaltable,P=u.lua_pushinteger,C=u.lua_pushliteral,D=u.lua_pushnil,V=u.lua_pushstring,B=u.lua_pushvalue,G=u.lua_rawequal,K=u.lua_rawget,F=u.lua_rawlen,j=u.lua_rawset,H=u.lua_remove,X=u.lua_replace,z=u.lua_rotate,Y=u.lua_setfield,J=u.lua_setmetatable,Z=u.lua_settop,q=u.lua_setupvalue,W=u.lua_stringtonumber,Q=u.lua_toboolean,$=u.lua_tolstring,tt=u.lua_tostring,et=u.lua_type,rt=u.lua_typename,nt=r(7),at=nt.luaL_argcheck,ut=nt.luaL_checkany,st=nt.luaL_checkinteger,ot=nt.luaL_checkoption,lt=nt.luaL_checkstack,it=nt.luaL_checktype,ct=nt.luaL_error,ft=nt.luaL_getmetafield,_t=nt.luaL_loadbufferx,pt=nt.luaL_loadfile,vt=nt.luaL_loadfilex,ht=nt.luaL_optinteger,Lt=nt.luaL_optstring,dt=nt.luaL_setfuncs,At=nt.luaL_tolstring,gt=nt.luaL_where,Tt=r(5),xt=Tt.to_jsstring,bt=Tt.to_luastring;if("function"==typeof TextDecoder){var kt="",Ot=new TextDecoder("utf-8");n=function(t){kt+=Ot.decode(t,{stream:!0})};var Et=new Uint8Array(0);a=function(){kt+=Ot.decode(Et),console.log(kt),kt=""}}else{var mt=[];n=function(t){try{t=xt(t)}catch(r){var e=new Uint8Array(t.length);e.set(t),t=e}mt.push(t)},a=function(){console.log.apply(console.log,mt),mt=[]}}var Ut=["stop","restart","collect","count","step","setpause","setstepmul","isrunning"].map(function(t){return bt(t)}),Nt=function(t){return it(t,1,p),Z(t,2),R(t,1)?2:(D(t),1)},Rt=function(t){var e=st(t,2)+1;return P(t,e),x(t,1,e)===i?1:2},yt=function(t){var e=ht(t,2,1);return Z(t,1),et(t,1)===_&&e>0&&(gt(t,e),B(t,1),A(t,2)),g(t)},St=function(t,e,r){return e!==o&&e!==h?(w(t,0),B(t,-2),2):k(t)-r},wt=function(t,e,r){return e===o?(0!==r&&(B(t,r),q(t,-2,1)||S(t,1)),1):(D(t),O(t,-2),2)},It=function(t,e){return lt(t,2,"too many nested functions"),B(t,1),L(t,0,1),E(t,-1)?(S(t,1),null):(U(t,-1)||ct(t,bt("reader function must return a string")),X(t,5),tt(t,5))},Mt=function(t,e,r){return k(t)-1},Pt={assert:function(t){return Q(t,1)?k(t):(ut(t,1),H(t,1),C(t,"assertion failed!"),Z(t,1),yt(t))},collectgarbage:function(t){ot(t,1,"collect",Ut),ht(t,2,0),ct(t,bt("lua_gc not implemented"))},dofile:function(t){var e=Lt(t,1,null);return Z(t,1),pt(t,e)!==o?g(t):(d(t,0,s,0,Mt),Mt(t))},error:yt,getmetatable:function(t){return ut(t,1),b(t,1)?(ft(t,1,bt("__metatable",!0)),1):(D(t),1)},ipairs:function(t){return ut(t,1),I(t,Rt),B(t,1),P(t,0),3},load:function(t){var e,r=tt(t,1),n=Lt(t,3,"bt"),a=m(t,4)?0:4;if(null!==r){var u=Lt(t,2,r);e=_t(t,r,r.length,u,n)}else{var s=Lt(t,2,"=(load)");it(t,1,l),Z(t,5),e=N(t,It,null,s,n)}return wt(t,e,a)},loadfile:function(t){var e=Lt(t,1,null),r=Lt(t,2,null),n=m(t,3)?0:3,a=vt(t,e,r);return wt(t,a,n)},next:Nt,pairs:function(t){return function(t,e,r,n){return ut(t,1),ft(t,1,e)===i?(I(t,n),B(t,1),r?P(t,0):D(t)):(B(t,1),L(t,1,3)),3}(t,bt("__pairs",!0),0,Nt)},pcall:function(t){ut(t,1),w(t,1),O(t,1);var e=y(t,k(t)-2,s,0,0,St);return St(t,e,0)},print:function(t){var e=k(t);T(t,bt("tostring",!0));for(var r=1;r<=e;r++){B(t,-1),B(t,r),L(t,1,1);var u=$(t,-1);if(null===u)return ct(t,bt("'tostring' must return a string to 'print'"));r>1&&n(bt("\t")),n(u),S(t,1)}return a(),0},rawequal:function(t){return ut(t,1),ut(t,2),w(t,G(t,1,2)),1},rawget:function(t){return it(t,1,p),ut(t,2),Z(t,2),K(t,1),1},rawlen:function(t){var e=et(t,1);return at(t,e===p||e===_,1,"table or string expected"),P(t,F(t,1)),1},rawset:function(t){return it(t,1,p),ut(t,2),ut(t,3),Z(t,3),j(t,1),1},select:function(t){var e=k(t);if(et(t,1)===_&&35===tt(t,1)[0])return P(t,e-1),1;var r=st(t,1);return r<0?r=e+r:r>e&&(r=e),at(t,1<=r,1,"index out of range"),e-r},setmetatable:function(t){var e=et(t,2);return it(t,1,p),at(t,e===i||e===p,2,"nil or table expected"),ft(t,1,bt("__metatable",!0))!==i?ct(t,bt("cannot change a protected metatable")):(Z(t,2),J(t,1),1)},tonumber:function(t){if(et(t,2)<=0){if(ut(t,1),et(t,1)===f)return Z(t,1),1;var e=tt(t,1);if(null!==e&&W(t,e)===e.length+1)return 1}else{var r=st(t,2);it(t,1,_);var n=tt(t,1);at(t,2<=r&&r<=36,2,"base out of range");var a=function(t,e){try{t=xt(t)}catch(t){return null}var r=/^[\t\v\f \n\r]*([+-]?)0*([0-9A-Za-z]+)[\t\v\f \n\r]*$/.exec(t);if(!r)return null;var n=parseInt(r[1]+r[2],e);return isNaN(n)?null:0|n}(n,r);if(null!==a)return P(t,a),1}return D(t),1},tostring:function(t){return ut(t,1),At(t,1),1},type:function(t){var e=et(t,1);return at(t,e!==c,1,"value expected"),V(t,rt(t,e)),1},xpcall:function(t){var e=k(t);it(t,2,l),w(t,1),B(t,1),z(t,3,2);var r=y(t,e-2,s,2,2,St);return St(t,r,2)}};t.exports.luaopen_base=function(t){return M(t),dt(t,Pt,0),B(t,-1),Y(t,-2,bt("_G")),C(t,v),Y(t,-2,bt("_VERSION")),1}},function(t,e,r){"use strict";var n=r(2),a=n.LUA_OK,u=n.LUA_TFUNCTION,s=n.LUA_TSTRING,o=n.LUA_YIELD,l=n.lua_Debug,i=n.lua_checkstack,c=n.lua_concat,f=n.lua_error,_=n.lua_getstack,p=n.lua_gettop,v=n.lua_insert,h=n.lua_isyieldable,L=n.lua_newthread,d=n.lua_pop,A=n.lua_pushboolean,g=n.lua_pushcclosure,T=n.lua_pushliteral,x=n.lua_pushthread,b=n.lua_pushvalue,k=n.lua_resume,O=n.lua_status,E=n.lua_tothread,m=n.lua_type,U=n.lua_upvalueindex,N=n.lua_xmove,R=n.lua_yield,y=r(7),S=y.luaL_argcheck,w=y.luaL_checktype,I=y.luaL_newlib,M=y.luaL_where,P=function(t){var e=E(t,1);return S(t,e,1,"thread expected"),e},C=function(t,e,r){if(!i(e,r))return T(t,"too many arguments to resume"),-1;if(O(e)===a&&0===p(e))return T(t,"cannot resume dead coroutine"),-1;N(t,e,r);var n=k(e,t,r);if(n===a||n===o){var u=p(e);return i(t,u+1)?(N(e,t,u),u):(d(e,u),T(t,"too many results to resume"),-1)}return N(e,t,1),-1},D=function(t){var e=E(t,U(1)),r=C(t,e,p(t));return r<0?(m(t,-1)===s&&(M(t,1),v(t,-2),c(t,2)),f(t)):r},V=function(t){w(t,1,u);var e=L(t);return b(t,1),N(t,e,1),1},B={create:V,isyieldable:function(t){return A(t,h(t)),1},resume:function(t){var e=P(t),r=C(t,e,p(t)-1);return r<0?(A(t,0),v(t,-2),2):(A(t,1),v(t,-(r+1)),r+1)},running:function(t){return A(t,x(t)),2},status:function(t){var e=P(t);if(t===e)T(t,"running");else switch(O(e)){case o:T(t,"suspended");break;case a:var r=new l;_(e,0,r)>0?T(t,"normal"):0===p(e)?T(t,"dead"):T(t,"suspended");break;default:T(t,"dead")}return 1},wrap:function(t){return V(t),g(t,D,1),1},yield:function(t){return R(t,p(t))}};t.exports.luaopen_coroutine=function(t){return I(t,B),1}},function(t,e,r){"use strict";var n=r(3).LUA_MAXINTEGER,a=r(2),u=a.LUA_OPEQ,s=a.LUA_OPLT,o=a.LUA_TFUNCTION,l=a.LUA_TNIL,i=a.LUA_TTABLE,c=a.lua_call,f=a.lua_checkstack,_=a.lua_compare,p=a.lua_createtable,v=a.lua_geti,h=a.lua_getmetatable,L=a.lua_gettop,d=a.lua_insert,A=a.lua_isnil,g=a.lua_isnoneornil,T=a.lua_isstring,x=a.lua_pop,b=a.lua_pushinteger,k=a.lua_pushnil,O=a.lua_pushstring,E=a.lua_pushvalue,m=a.lua_rawget,U=a.lua_setfield,N=a.lua_seti,R=a.lua_settop,y=a.lua_toboolean,S=a.lua_type,w=r(7),I=w.luaL_Buffer,M=w.luaL_addlstring,P=w.luaL_addvalue,C=w.luaL_argcheck,D=w.luaL_buffinit,V=w.luaL_checkinteger,B=w.luaL_checktype,G=w.luaL_error,K=w.luaL_len,F=w.luaL_newlib,j=w.luaL_opt,H=w.luaL_optinteger,X=w.luaL_optlstring,z=w.luaL_pushresult,Y=w.luaL_typename,J=r(17),Z=r(5).to_luastring,q=function(t,e,r){return O(t,e),m(t,-r)!==l},W=function(t,e,r){if(S(t,e)!==i){var n=1;!h(t,e)||1&r&&!q(t,Z("__index",!0),++n)||2&r&&!q(t,Z("__newindex",!0),++n)||4&r&&!q(t,Z("__len",!0),++n)?B(t,e,i):x(t,n)}},Q=function(t,e,r){return W(t,e,4|r),K(t,e)},$=function(t,e,r){v(t,1,r),T(t,-1)||G(t,Z("invalid value (%s) at index %d in table for 'concat'"),Y(t,-1),r),P(e)},tt=function(t,e,r){N(t,1,e),N(t,1,r)},et=function(t,e,r){if(A(t,2))return _(t,e,r,s);E(t,2),E(t,e-1),E(t,r-2),c(t,2,1);var n=y(t,-1);return x(t,1),n},rt=function(t,e,r){for(var n=e,a=r-1;;){for(;v(t,1,++n),et(t,-1,-2);)n==r-1&&G(t,Z("invalid order function for sorting")),x(t,1);for(;v(t,1,--a),et(t,-3,-1);)ae;n--)v(t,1,n-1),N(t,1,n);break;default:return G(t,"wrong number of arguments to 'insert'")}return N(t,1,e),0},move:function(t){var e=V(t,2),r=V(t,3),a=V(t,4),s=g(t,5)?1:5;if(W(t,1,1),W(t,s,2),r>=e){C(t,e>0||rr||a<=e||1!==s&&1!==_(t,1,s,u))for(var l=0;l=0;i--)v(t,1,e+i),N(t,s,a+i)}return E(t,s),1},pack:function(t){var e=L(t);p(t,e,1),d(t,1);for(var r=e;r>=1;r--)N(t,1,r);return b(t,e),U(t,1,Z("n")),1},remove:function(t){var e=Q(t,1,3),r=H(t,2,e);for(r!==e&&C(t,1<=r&&r<=e+1,1,"position out of bounds"),v(t,1,r);r1&&(C(t,es&&(a=Math.floor(4294967296*Math.random()))}}(t,1,e,0)),0},unpack:function(t){var e=H(t,2,1),r=j(t,V,3,K(t,1));if(e>r)return 0;var n=r-e;if(n>=Number.MAX_SAFE_INTEGER||!f(t,++n))return G(t,Z("too many results to unpack"));for(;e0?A(r,45):(c=-c,A(r,43)),V(r,Math.floor(c/60),48),V(r,c%60,48)}u+=s}}(t,u,e,r),U(u)}return 1},difftime:function(t){var e=G(t,1),r=G(t,2);return _(t,e-r),1},time:function(t){var e;return l(t,1)?e=new Date:(k(t,1,u),v(t,1),e=new Date(P(t,"year",-1,0),P(t,"month",-1,1),P(t,"day",-1,0),P(t,"hour",12,0),P(t,"min",0,0),P(t,"sec",0,0)),I(t,e)),f(t,Math.floor(e/1e3)),1}};K.clock=function(t){return _(t,performance.now()/1e3),1};t.exports.luaopen_os=function(t){return E(t,K),1}},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var a=r(38).sprintf,u=r(3),s=u.LUA_INTEGER_FMT,o=u.LUA_INTEGER_FRMLEN,l=u.LUA_MININTEGER,i=u.LUA_NUMBER_FMT,c=u.LUA_NUMBER_FRMLEN,f=u.frexp,_=u.lua_getlocaledecpoint,p=r(2),v=p.LUA_TBOOLEAN,h=p.LUA_TFUNCTION,L=p.LUA_TNIL,d=p.LUA_TNUMBER,A=p.LUA_TSTRING,g=p.LUA_TTABLE,T=p.lua_call,x=p.lua_createtable,b=p.lua_dump,k=p.lua_gettable,O=p.lua_gettop,E=p.lua_isinteger,m=p.lua_isstring,U=p.lua_pop,N=p.lua_pushcclosure,R=p.lua_pushinteger,y=p.lua_pushlightuserdata,S=p.lua_pushliteral,w=p.lua_pushlstring,I=p.lua_pushnil,M=p.lua_pushnumber,P=p.lua_pushstring,C=p.lua_pushvalue,D=p.lua_remove,V=p.lua_setfield,B=p.lua_setmetatable,G=p.lua_settop,K=p.lua_toboolean,F=p.lua_tointeger,j=p.lua_tonumber,H=p.lua_tostring,X=p.lua_touserdata,z=p.lua_type,Y=p.lua_upvalueindex,J=r(7),Z=J.luaL_Buffer,q=J.luaL_addchar,W=J.luaL_addlstring,Q=J.luaL_addsize,$=J.luaL_addstring,tt=J.luaL_addvalue,et=J.luaL_argcheck,rt=J.luaL_argerror,nt=J.luaL_buffinit,at=J.luaL_buffinitsize,ut=J.luaL_checkinteger,st=J.luaL_checknumber,ot=J.luaL_checkstack,lt=J.luaL_checkstring,it=J.luaL_checktype,ct=J.luaL_error,ft=J.luaL_newlib,_t=J.luaL_optinteger,pt=J.luaL_optstring,vt=J.luaL_prepbuffsize,ht=J.luaL_pushresult,Lt=J.luaL_pushresultsize,dt=J.luaL_tolstring,At=J.luaL_typename,gt=r(17),Tt=r(5),xt=Tt.luastring_eq,bt=Tt.luastring_indexOf,kt=Tt.to_jsstring,Ot=Tt.to_luastring,Et="%".charCodeAt(0),mt=function(t){var e=bt(t,0);return e>-1?e:t.length},Ut=function(t,e){return t>=0?t:0-t>e?0:e+t+1},Nt=function(t,e,r,n){return W(n,e,r),0},Rt=c.length+1,yt=function(t,e,r){var n=function(t){if(Object.is(t,1/0))return Ot("inf");if(Object.is(t,-1/0))return Ot("-inf");if(Number.isNaN(t))return Ot("nan");if(0===t){var e=a(i+"x0p+0",t);return Object.is(t,-0)&&(e="-"+e),Ot(e)}var r="",n=f(t),u=n[0],s=n[1];return u<0&&(r+="-",u=-u),r+="0x",r+=(2*u).toString(16),r+=a("p%+d",s-=1),Ot(r)}(r);if(65===e[Rt])for(var u=0;u=97&&(n[u]=223&s)}else 97!==e[Rt]&&ct(t,Ot("modifiers for format '%%a'/'%%A' not implemented"));return n},St=Ot("-+ #0"),wt=function(t){return 97<=t&&t<=122||65<=t&&t<=90},It=function(t){return 48<=t&&t<=57},Mt=function(t){return 0<=t&&t<=31||127===t},Pt=function(t){return 33<=t&&t<=126},Ct=function(t){return 97<=t&&t<=122},Dt=function(t){return 65<=t&&t<=90},Vt=function(t){return 97<=t&&t<=122||65<=t&&t<=90||48<=t&&t<=57},Bt=function(t){return Pt(t)&&!Vt(t)},Gt=function(t){return 32===t||t>=9&&t<=13},Kt=function(t){return 48<=t&&t<=57||65<=t&&t<=70||97<=t&&t<=102},Ft=function(t,e,r){switch(z(t,r)){case A:var n=H(t,r);!function(t,e,r){q(t,34);for(var n=0;r--;){if(34===e[n]||92===e[n]||10===e[n])q(t,92),q(t,e[n]);else if(Mt(e[n])){var a=""+e[n];It(e[n+1])&&(a="0".repeat(3-a.length)+a),$(t,Ot("\\"+a))}else q(t,e[n]);n++}q(t,34)}(e,n,n.length);break;case d:var u;if(E(t,r)){var i=F(t,r);u=Ot(a(i===l?"0x%"+o+"x":s,i))}else{var c=j(t,r);(function(t){if(bt(t,46)<0){var e=_(),r=bt(t,e);r&&(t[r]=46)}})(u=yt(t,Ot("%".concat(o,"a")),c))}$(e,u);break;case L:case v:dt(t,r),tt(e);break;default:rt(t,r,Ot("value has no literal form"))}},jt=function(t,e,r,n){for(var a=r;0!==e[a]&&bt(St,e[a])>=0;)a++;a-r>=St.length&&ct(t,Ot("invalid format (repeated flags)")),It(e[a])&&a++,It(e[a])&&a++,46===e[a]&&(It(e[++a])&&a++,It(e[a])&&a++),It(e[a])&&ct(t,Ot("invalid format (width or precision too long)")),n[0]=37;for(var u=0;u=t.s.length||!zt(t.s[t.off]))return e;var r=0;do{r=10*r+(t.s[t.off++]-48)}while(t.off16||n<=0)&&ct(t.L,Ot("integral size (%d) out of limits [1,%d]"),n,16),n},Zt=function(t,e){var r={opt:e.s[e.off++],size:0};switch(r.opt){case 98:return r.size=1,r.opt=0,r;case 66:return r.size=1,r.opt=1,r;case 104:return r.size=2,r.opt=0,r;case 72:return r.size=2,r.opt=1,r;case 108:return r.size=4,r.opt=0,r;case 76:return r.size=4,r.opt=1,r;case 106:return r.size=4,r.opt=0,r;case 74:case 84:return r.size=4,r.opt=1,r;case 102:return r.size=4,r.opt=2,r;case 100:case 110:return r.size=8,r.opt=2,r;case 105:return r.size=Jt(t,e,4),r.opt=0,r;case 73:return r.size=Jt(t,e,4),r.opt=1,r;case 115:return r.size=Jt(t,e,4),r.opt=4,r;case 99:return r.size=Yt(e,-1),-1===r.size&&ct(t.L,Ot("missing size for format option 'c'")),r.opt=3,r;case 122:return r.opt=5,r;case 120:return r.size=1,r.opt=6,r;case 88:return r.opt=7,r;case 32:break;case 60:t.islittle=!0;break;case 62:t.islittle=!1;break;case 61:t.islittle=!0;break;case 33:t.maxalign=Jt(t,e,8);break;default:ct(t.L,Ot("invalid format option '%c'"),r.opt)}return r.opt=8,r},qt=function(t,e,r){var n={opt:NaN,size:NaN,ntoalign:NaN},a=Zt(t,r);n.size=a.size,n.opt=a.opt;var u=n.size;if(7===n.opt)if(r.off>=r.s.length||0===r.s[r.off])rt(t.L,1,Ot("invalid next option for option 'X'"));else{var s=Zt(t,r);u=s.size,3!==(s=s.opt)&&0!==u||rt(t.L,1,Ot("invalid next option for option 'X'"))}return u<=1||3===n.opt?n.ntoalign=0:(u>t.maxalign&&(u=t.maxalign),0!=(u&u-1)&&rt(t.L,1,Ot("format asks for alignment not power of 2")),n.ntoalign=u-(e&u-1)&u-1),n},Wt=function(t,e,r,n,a){var u=vt(t,n);u[r?0:n-1]=255&e;for(var s=1;s>=8,u[r?s:n-1-s]=255&e;if(a&&n>4)for(var o=4;o=0;o--)u<<=8,u|=e[r?o:n-1-o];if(n<4){if(a){var l=1<<8*n-1;u=(u^l)-l}}else if(n>4)for(var i=!a||u>=0?0:255,c=s;c=n);for(var a=new DataView(new ArrayBuffer(n)),u=0;u=t.src_end)return!1;var a=t.src[e];switch(t.p[r]){case 46:return!0;case Et:return ne(a,t.p[r+1]);case 91:return ae(t,a,r,n-1);default:return t.p[r]===a}},se=function(t,e,r){if(r>=t.p_end-1&&ct(t.L,Ot("malformed pattern (missing arguments to '%%b'")),t.src[e]!==t.p[r])return null;for(var n=t.p[r],a=t.p[r+1],u=1;++e=0;){var u=_e(t,e+a,n+1);if(u)return u;a--}return null},le=function(t,e,r,n){for(;;){var a=_e(t,e,n+1);if(null!==a)return a;if(!ue(t,e,r,n))return null;e++}},ie=function(t,e,r,n){var a,u=t.level;return u>=32&&ct(t.L,Ot("too many captures")),t.capture[u]=t.capture[u]?t.capture[u]:{},t.capture[u].init=e,t.capture[u].len=n,t.level=u+1,null===(a=_e(t,e,r))&&t.level--,a},ce=function(t,e,r){var n,a=function(t){var e=t.level;for(e--;e>=0;e--)if(-1===t.capture[e].len)return e;return ct(t.L,Ot("invalid pattern capture"))}(t);return t.capture[a].len=e-t.capture[a].init,null===(n=_e(t,e,r))&&(t.capture[a].len=-1),n},fe=function(t,e,r){r=function(t,e){return(e-=49)<0||e>=t.level||-1===t.capture[e].len?ct(t.L,Ot("invalid capture index %%%d"),e+1):e}(t,r);var n=t.capture[r].len;return t.src_end-e>=n&&function(t,e,r,n,a){return xt(t.subarray(e,e+a),r.subarray(n,n+a))}(t.src,t.capture[r].init,t.src,e,n)?e+n:null},_e=function t(e,r,n){var a=!1,u=!0;for(0==e.matchdepth--&&ct(e.L,Ot("pattern too complex"));u||a;)if(u=!1,n!==e.p_end)switch(a?void 0:e.p[n]){case 40:r=41===e.p[n+1]?ie(e,r,n+2,-2):ie(e,r,n+1,-1);break;case 41:r=ce(e,r,n+1);break;case 36:if(n+1!==e.p_end){a=!0;break}r=e.src.length-r==0?r:null;break;case Et:switch(e.p[n+1]){case 98:null!==(r=se(e,r,n+2))&&(n+=4,u=!0);break;case 102:n+=2,91!==e.p[n]&&ct(e.L,Ot("missing '[' after '%%f' in pattern"));var s=re(e,n),o=r===e.src_init?0:e.src[r-1];if(!ae(e,o,n,s-1)&&ae(e,r===e.src_end?0:e.src[r],n,s-1)){n=s,u=!0;break}r=null;break;case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:null!==(r=fe(e,r,e.p[n+1]))&&(n+=2,u=!0);break;default:a=!0}break;default:a=!1;var l=re(e,n);if(ue(e,r,n,l))switch(e.p[l]){case 63:var i;null!==(i=t(e,r+1,l+1))?r=i:(n=l+1,u=!0);break;case 43:r++;case 42:r=oe(e,r,n,l);break;case 45:r=le(e,r,n,l);break;default:r++,n=l,u=!0}else{if(42===e.p[l]||63===e.p[l]||45===e.p[l]){n=l+1,u=!0;break}r=null}}return e.matchdepth++,r},pe=function(t,e,r,n){if(e>=t.level)0===e?w(t.L,t.src.subarray(r,n),n-r):ct(t.L,Ot("invalid capture index %%%d"),e+1);else{var a=t.capture[e].len;-1===a&&ct(t.L,Ot("unfinished capture")),-2===a?R(t.L,t.capture[e].init-t.src_init+1):w(t.L,t.src.subarray(t.capture[e].init),a)}},ve=function(t,e,r){var n=0===t.level&&t.src.subarray(e)?1:t.level;ot(t.L,n,"too many captures");for(var a=0;aa+1)return I(t),1;if(e&&(K(t,4)||function(t,e){for(var r=0;r>>0,a=e.length;if(0===a)return n;for(;-1!==(n=t.indexOf(e[0],n));n++)if(xt(t.subarray(n,n+a),e))return n;return-1}(r.subarray(s-1),n,0);if(o>-1)return R(t,s+o),R(t,s+o+u-1),2}else{var l=new ee(t),i=s-1,c=94===n[0];c&&(n=n.subarray(1),u--),he(l,t,r,a,n,u);do{var f;if(Le(l),null!==(f=_e(l,i,0)))return e?(R(t,i+1),R(t,f),ve(l,null,0)+2):ve(l,i,f)}while(i++r&&(a=r),n>a)return 0;if(a-n>=Number.MAX_SAFE_INTEGER)return ct(t,"string slice too long");var u=a-n+1;ot(t,u,"string slice too long");for(var s=0;s=0&&u<=255,"value out of range"),n[a-1]=u}return Lt(r,e),1},dump:function(t){var e=new Z,r=K(t,2);return it(t,1,h),G(t,1),nt(t,e),0!==b(t,Nt,e,r)?ct(t,Ot("unable to dump given function")):(ht(e),1)},find:function(t){return de(t,1)},format:function(t){var e=O(t),r=1,n=lt(t,r),u=0,s=new Z;for(nt(t,s);ue&&rt(t,r,Ot("no value")),u=jt(t,n,u,l),String.fromCharCode(n[u++])){case"c":q(s,ut(t,r));break;case"d":case"i":case"o":case"u":case"x":case"X":var i=ut(t,r);Ht(l,Ot(o,!0)),$(s,Ot(a(String.fromCharCode.apply(String,l),i)));break;case"a":case"A":Ht(l,Ot(o,!0)),$(s,yt(t,l,st(t,r)));break;case"e":case"E":case"f":case"g":case"G":var c=st(t,r);Ht(l,Ot(o,!0)),$(s,Ot(a(String.fromCharCode.apply(String,l),c)));break;case"q":Ft(t,s,r);break;case"s":var f=dt(t,r);l.length<=2||0===l[2]?tt(s):(et(t,f.length===mt(f),r,"string contains zeros"),bt(l,46)<0&&f.length>=100?tt(s):($(s,Ot(a(String.fromCharCode.apply(String,l),kt(f)))),U(t,1)));break;default:return ct(t,Ot("invalid option '%%%c' to 'format'"),n[u-1])}}return ht(s),1},gmatch:function(t){var e=lt(t,1),r=lt(t,2),a=e.length,u=r.length;G(t,2);var s=new function t(){n(this,t),this.src=NaN,this.p=NaN,this.lastmatch=NaN,this.ms=new ee};return y(t,s),he(s.ms,t,e,a,r,u),s.src=0,s.p=0,s.lastmatch=null,N(t,Ae,3),1},gsub:function(t){var e=lt(t,1),r=e.length,n=lt(t,2),a=n.length,u=null,s=z(t,3),o=_t(t,4,r+1),l=94===n[0],i=0,c=new ee(t),f=new Z;for(et(t,s===d||s===A||s===h||s===g,3,"string/function/table expected"),nt(t,f),l&&(n=n.subarray(1),a--),he(c,t,e,r,n,a),e=0,n=0;i0;)q(e,0);switch(a++,o){case 0:var c=ut(t,a);if(l<4){var f=1<<8*l-1;et(t,-f<=c&&c>>0<1<<8*l,a,"unsigned overflow"),Wt(e,_>>>0,r.islittle,l,!1);break;case 2:var p=vt(e,l),v=st(t,a),h=new DataView(p.buffer,p.byteOffset,p.byteLength);4===l?h.setFloat32(0,v,r.islittle):h.setFloat64(0,v,r.islittle),Q(e,l);break;case 3:var L=lt(t,a),d=L.length;for(et(t,d<=l,a,"string longer than given size"),W(e,L,d);d++=4||g<1<<8*l,a,"string length does not fit in given size"),Wt(e,g,r.islittle,l,0),W(e,A,g),u+=g;break;case 5:var T=lt(t,a),x=T.length;et(t,bt(T,0)<0,a,"strings contains zeros"),W(e,T,x),q(e,0),u+=x+1;break;case 6:q(e,0);case 7:case 8:a--}}return ht(e),1},packsize:function(t){for(var e=new Xt(t),r={s:lt(t,1),off:0},n=0;r.off2147483647/n)return ct(t,Ot("resulting string too large"));for(var s=n*r+(n-1)*u,o=new Z,l=at(t,o,s),i=0;n-- >1;)l.set(e,i),i+=r,u>0&&(l.set(a,i),i+=u);l.set(e,i),Lt(o,s)}return 1},reverse:function(t){for(var e=lt(t,1),r=e.length,n=new Uint8Array(r),a=0;ar&&(a=r),n<=a?P(t,e.subarray(n-1,n-1+(a-n+1))):S(t,""),1},unpack:function(t){var e=new Xt(t),r={s:lt(t,1),off:0},n=lt(t,2),a=n.length,u=Ut(_t(t,3,1),a)-1,s=0;for(et(t,u<=a&&u>=0,3,"initial position out of string");r.offa&&rt(t,2,Ot("data string too short")),u+=c,ot(t,2,"too many results"),s++,l){case 0:case 1:var f=Qt(t,n.subarray(u),e.islittle,i,0===l);R(t,f);break;case 2:var _=$t(0,n.subarray(u),e.islittle,i);M(t,_);break;case 3:P(t,n.subarray(u,u+i));break;case 4:var p=Qt(t,n.subarray(u),e.islittle,i,0);et(t,u+p+i<=a,2,"data string too short"),P(t,n.subarray(u+i,u+i+p)),u+=p;break;case 5:var v=bt(n,0,u);-1===v&&(v=n.length-u),P(t,n.subarray(u,v)),u=v+1;break;case 7:case 6:case 8:s--}u+=i}return R(t,u+1),s+1},upper:function(t){for(var e=lt(t,1),r=e.length,n=new Uint8Array(r),a=0;a=0?t:0-t>e?0:e+t+1},y=[255,127,2047,65535],S=function(t,e){var r=t[e],n=0;if(r<128)n=r;else{for(var a=0;64&r;){var u=t[e+ ++a];if(128!=(192&u))return null;n=n<<6|63&u,r<<=1}if(n|=(127&r)<<5*a,a>3||n>1114111||n<=y[a])return null;e+=a}return{code:n,pos:e+1}},w=U("%U"),I=function(t,e){var r=A(t,e);L(t,0<=r&&r<=1114111,e,"value out of range"),s(t,w,r)},M=function(t){var e=T(t,1),r=e.length,n=_(t,2)-1;if(n<0)n=0;else if(n=r)return 0;var a=S(e,n);return null===a||N(e[a.pos])?x(t,U("invalid UTF-8 code")):(o(t,n+1),o(t,a.code),2)},P={char:function(t){var e=a(t);if(1===e)I(t,1);else{var r=new v;d(t,r);for(var n=1;n<=e;n++)I(t,n),h(r);O(r)}return 1},codepoint:function(t){var e=T(t,1),r=R(k(t,2,1),e.length),n=R(k(t,3,r),e.length);if(L(t,r>=1,2,"out of range"),L(t,n<=e.length,3,"out of range"),r>n)return 0;if(n-r>=Number.MAX_SAFE_INTEGER)return x(t,"string slice too long");var a=n-r+1;for(g(t,a,"string slice too long"),a=0,r-=1;r=0?1:e.length+1;if(n=R(k(t,3,n),e.length),L(t,1<=n&&--n<=e.length,3,"position out of range"),0===r)for(;n>0&&N(e[n]);)n--;else if(N(e[n])&&x(t,"initial position is a continuation byte"),r<0)for(;r<0&&n>0;){do{n--}while(n>0&&N(e[n]));r++}else for(r--;r>0&&n=1,1,"value expected");for(var n=2;n<=e;n++)o(t,r,n,u)&&(r=n);return L(t,r),1},min:function(t){var e=l(t),r=1;k(t,e>=1,1,"value expected");for(var n=2;n<=e;n++)o(t,n,r,u)&&(r=n);return L(t,r),1},modf:function(t){if(i(t,1))A(t,1),h(t,0);else{var e=U(t,1),r=e<0?Math.ceil(e):Math.floor(e);D(t,r),h(t,e===r?0:e-r)}return 2},rad:function(t){return h(t,U(t,1)*(Math.PI/180)),1},random:function(t){var e,r,a=void 0===n?Math.random():C()/2147483648;switch(l(t)){case 0:return h(t,a),1;case 1:e=1,r=m(t,1);break;case 2:e=m(t,1),r=m(t,2);break;default:return N(t,"wrong number of arguments")}return k(t,e<=r,1,"interval is empty"),k(t,e>=0||r<=w+e,1,"interval too large"),a*=r-e+1,_(t,Math.floor(a)+e),1},randomseed:function(t){return function(t){0==(n=0|t)&&(n=1)}(U(t,1)),C(),0},sin:function(t){return h(t,Math.sin(U(t,1))),1},sqrt:function(t){return h(t,Math.sqrt(U(t,1))),1},tan:function(t){return h(t,Math.tan(U(t,1))),1},tointeger:function(t){var e=T(t,1);return!1!==e?_(t,e):(E(t,1),v(t)),1},type:function(t){return x(t,1)===s?i(t,1)?p(t,"integer"):p(t,"float"):(E(t,1),v(t)),1},ult:function(t){var e=m(t,1),r=m(t,2);return f(t,e>=0?r<0||e=0?C(t,e.currentline):B(t),xt.lua_assert(T(t,Ot("lS"),e)),h(t,2,0))},Ct={gethook:function(t){var e=mt(t).thread,r=new Uint8Array(5),n=g(e),a=d(e);null===a?B(t):a!==Pt?V(t,"external hook"):(F(t,i,It),rt(t,-1).get(e)(t));return G(t,function(t,e){var r=0;return t&u&&(e[r++]=99),t&l&&(e[r++]=114),t&o&&(e[r++]=108),e.subarray(0,r)}(n,r)),C(t,A(e)),3},getinfo:function(t){var e=new v,r=mt(t),n=r.arg,a=r.thread,u=At(t,n+2,"flnStu");if(Et(t,a,3),N(t,n+1))u=P(t,Ot(">%s"),u),K(t,n+1),st(t,a,1);else if(!k(a,ft(t,n+1),e))return B(t),1;return T(a,u,e)||it(t,n+2,"invalid option"),S(t),kt(u,83)>-1&&(Ut(t,Ot("source",!0),e.source),Ut(t,Ot("short_src",!0),e.short_src),Nt(t,Ot("linedefined",!0),e.linedefined),Nt(t,Ot("lastlinedefined",!0),e.lastlinedefined),Ut(t,Ot("what",!0),e.what)),kt(u,108)>-1&&Nt(t,Ot("currentline",!0),e.currentline),kt(u,117)>-1&&(Nt(t,Ot("nups",!0),e.nups),Nt(t,Ot("nparams",!0),e.nparams),Rt(t,Ot("isvararg",!0),e.isvararg)),kt(u,110)>-1&&(Ut(t,Ot("name",!0),e.name),Ut(t,Ot("namewhat",!0),e.namewhat)),kt(u,116)>-1&&Rt(t,Ot("istailcall",!0),e.istailcall),kt(u,76)>-1&&yt(t,a,Ot("activelines",!0)),kt(u,102)>-1&&yt(t,a,Ot("func",!0)),1},getlocal:function(t){var e=mt(t),r=e.thread,n=e.arg,a=new v,u=ft(t,n+2);if(N(t,n+1))return K(t,n+1),G(t,x(t,null,u)),1;var s=ft(t,n+1);if(!k(r,s,a))return it(t,n+1,"level out of range");Et(t,r,1);var o=x(r,a,u);return o?(st(r,t,1),G(t,o),H(t,-2,1),2):(B(t),1)},getmetatable:function(t){return ct(t,1),b(t,1)||B(t),1},getregistry:function(t){return K(t,i),1},getupvalue:function(t){return St(t,1)},getuservalue:function(t){return nt(t,1)!==p?B(t):E(t,1),1},sethook:function(t){var e,r,n,a,_=mt(t),p=_.thread,v=_.arg;if(R(t,v+1))Z(t,v+1),n=null,e=0,r=0;else{var h=_t(t,v+2);pt(t,v+1,c),r=dt(t,v+3,0),n=Pt,e=function(t,e){var r=0;return kt(t,99)>-1&&(r|=u),kt(t,114)>-1&&(r|=l),kt(t,108)>-1&&(r|=o),e>0&&(r|=s),r}(h,r)}F(t,i,It)===f?(a=new WeakMap,D(t,a),j(t,i,It)):a=rt(t,-1);var L=$(t,v+1);return a.set(p,L),z(p,n,e,r),0},setlocal:function(t){var e=mt(t),r=e.thread,n=e.arg,a=new v,u=ft(t,n+1),s=ft(t,n+2);if(!k(r,u,a))return it(t,n+1,"level out of range");ct(t,n+3),Z(t,n+3),Et(t,r,1),st(t,r,1);var o=Y(r,a,s);return null===o&&I(r,1),G(t,o),1},setmetatable:function(t){var e=nt(t,2);return lt(t,e==f||e==_,2,"nil or table expected"),Z(t,2),J(t,1),1},setupvalue:function(t){return ct(t,3),St(t,0)},setuservalue:function(t){return pt(t,1,p),ct(t,2),Z(t,2),W(t,1),1},traceback:function(t){var e=mt(t),r=e.thread,n=e.arg,a=tt(t,n+1);if(null!==a||R(t,n+1)){var u=dt(t,n+2,t===r?1:0);gt(t,r,a,u)}else K(t,n+1);return 1},upvalueid:function(t){var e=wt(t,1,2);return D(t,at(t,1,e)),1},upvaluejoin:function(t){var e=wt(t,1,2),r=wt(t,3,4);return lt(t,!U(t,1),1,"Lua function expected"),lt(t,!U(t,3),3,"Lua function expected"),ut(t,1,e,3,r),0}};"undefined"!=typeof window&&(n=function(){var t=prompt("lua_debug>","");return null!==t?t:""}),n&&(Ct.debug=function(t){for(;;){var e=n();if("cont"===e)return 0;if(0!==e.length){var r=Ot(e);(ht(t,r,r.length,Ot("=(debug command)",!0))||w(t,0,0,0))&&Tt(Q(t,-1),"\n"),Z(t,0)}}});t.exports.luaopen_debug=function(t){return Lt(t,Ct),1}},function(t,e,r){"use strict";function n(t){return(n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var a,u=r(3),s=u.LUA_DIRSEP,o=u.LUA_EXEC_DIR,l=u.LUA_JSPATH_DEFAULT,i=u.LUA_PATH_DEFAULT,c=u.LUA_PATH_MARK,f=u.LUA_PATH_SEP,_=r(2),p=_.LUA_OK,v=_.LUA_REGISTRYINDEX,h=_.LUA_TNIL,L=_.LUA_TTABLE,d=_.lua_callk,A=_.lua_createtable,g=_.lua_getfield,T=_.lua_insert,x=_.lua_isfunction,b=_.lua_isnil,k=_.lua_isstring,O=_.lua_newtable,E=_.lua_pop,m=_.lua_pushboolean,U=_.lua_pushcclosure,N=_.lua_pushcfunction,R=_.lua_pushfstring,y=_.lua_pushglobaltable,S=_.lua_pushlightuserdata,w=_.lua_pushliteral,I=_.lua_pushlstring,M=_.lua_pushnil,P=_.lua_pushstring,C=_.lua_pushvalue,D=_.lua_rawgeti,V=_.lua_rawgetp,B=_.lua_rawseti,G=_.lua_rawsetp,K=_.lua_remove,F=_.lua_setfield,j=_.lua_setmetatable,H=_.lua_settop,X=_.lua_toboolean,z=_.lua_tostring,Y=_.lua_touserdata,J=_.lua_upvalueindex,Z=r(7),q=Z.LUA_LOADED_TABLE,W=Z.LUA_PRELOAD_TABLE,Q=Z.luaL_Buffer,$=Z.luaL_addvalue,tt=Z.luaL_buffinit,et=Z.luaL_checkstring,rt=Z.luaL_error,nt=Z.luaL_getsubtable,at=Z.luaL_gsub,ut=Z.luaL_len,st=Z.luaL_loadfile,ot=Z.luaL_newlib,lt=Z.luaL_optstring,it=Z.luaL_pushresult,ct=Z.luaL_setfuncs,ft=r(17),_t=r(5),pt=_t.luastring_indexOf,vt=_t.to_jsstring,ht=_t.to_luastring,Lt=_t.to_uristring,dt=r(0),At="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:(0,eval)("this"),gt=ht("__JSLIBS__"),Tt=s,xt=s,bt=ht("luaopen_"),kt=ht("_"),Ot=ht("");a=function(t,e,r){e=Lt(e);var a=new XMLHttpRequest;if(a.open("GET",e,!1),a.send(),a.status<200||a.status>=300)return P(t,ht("".concat(a.status,": ").concat(a.statusText))),null;var u,s=a.response;/\/\/[#@] sourceURL=/.test(s)||(s+=" //# sourceURL="+e);try{u=Function("fengari",s)}catch(e){return P(t,ht("".concat(e.name,": ").concat(e.message))),null}var o=u(dt);return"function"==typeof o||"object"===n(o)&&null!==o?o:void 0===o?At:(P(t,ht("library returned unexpected type (".concat(n(o),")"))),null)};var Et;Et=function(t){t=Lt(t);var e=new XMLHttpRequest;return e.open("GET",t,!1),e.send(),e.status>=200&&e.status<=299};var mt=function(t,e,r){var n=Rt(t,e);if(null===n){if(null===(n=a(t,e,r[0]==="*".charCodeAt(0))))return 1;yt(t,e,n)}if(r[0]==="*".charCodeAt(0))return m(t,1),0;var u=function(t,e,r){var n=e[vt(r)];return n&&"function"==typeof n?n:(R(t,ht("undefined symbol: %s"),r),null)}(t,n,r);return null===u?2:(N(t,u),0)},Ut=At,Nt=function(t,e,r,n){var a="".concat(r).concat(ft.LUA_VERSUFFIX);P(t,ht(a));var u=Ut[a];void 0===u&&(u=Ut[r]),void 0===u||function(t){g(t,v,ht("LUA_NOENV"));var e=X(t,-1);return E(t,1),e}(t)?P(t,n):(u=at(t,ht(u),ht(f+f,!0),ht(f+vt(Ot)+f,!0)),at(t,u,Ot,n),K(t,-2)),F(t,-3,e),E(t,1)},Rt=function(t,e){V(t,v,gt),g(t,-1,e);var r=Y(t,-1);return E(t,2),r},yt=function(t,e,r){V(t,v,gt),S(t,r),C(t,-1),F(t,-3,e),B(t,-2,ut(t,-2)+1),E(t,1)},St=function(t,e){for(;e[0]===f.charCodeAt(0);)e=e.subarray(1);if(0===e.length)return null;var r=pt(e,f.charCodeAt(0));return r<0&&(r=e.length),I(t,e,r),e.subarray(r)},wt=function(t,e,r,n,a){var u=new Q;for(tt(t,u),0!==n[0]&&(e=at(t,e,n,a));null!==(r=St(t,r));){var s=at(t,z(t,-1),ht(c,!0),e);if(K(t,-2),Et(s))return s;R(t,ht("\n\tno file '%s'"),s),K(t,-2),$(u)}return it(u),null},It=function(t,e,r,n){g(t,J(1),r);var a=z(t,-1);return null===a&&rt(t,ht("'package.%s' must be a string"),r),wt(t,e,a,ht("."),n)},Mt=function(t,e,r){return e?(P(t,r),2):rt(t,ht("error loading module '%s' from file '%s':\n\t%s"),z(t,1),r,z(t,-1))},Pt=function(t){var e=et(t,1),r=It(t,e,ht("path",!0),ht(xt,!0));return null===r?1:Mt(t,st(t,r)===p,r)},Ct=function(t,e,r){var n;r=at(t,r,ht("."),kt);var a=pt(r,"-".charCodeAt(0));if(a>=0){n=I(t,r,a),n=R(t,ht("%s%s"),bt,n);var u=mt(t,e,n);if(2!==u)return u;r=a+1}return n=R(t,ht("%s%s"),bt,r),mt(t,e,n)},Dt=function(t){var e=et(t,1),r=It(t,e,ht("jspath",!0),ht(Tt,!0));return null===r?1:Mt(t,0===Ct(t,r,e),r)},Vt=function(t){var e,r=et(t,1),n=pt(r,".".charCodeAt(0));if(n<0)return 0;I(t,r,n);var a=It(t,z(t,-1),ht("jspath",!0),ht(Tt,!0));return null===a?1:0!==(e=Ct(t,a,r))?2!=e?Mt(t,0,a):(P(t,ht("\n\tno module '%s' in file '%s'"),r,a),1):(P(t,a),2)},Bt=function(t){var e=et(t,1);return g(t,v,W),g(t,-1,e)===h&&R(t,ht("\n\tno field package.preload['%s']"),e),1},Gt=function t(e,r,n){for(;r===p?(D(e,3,n.i)===h&&(E(e,1),it(n.msg),rt(e,ht("module '%s' not found:%s"),n.name,z(e,-1))),P(e,n.name),d(e,1,2,n,t)):r=p,!x(e,-2);n.i++)k(e,-2)?(E(e,1),$(n.msg)):E(e,2);return n.k(e,p,n.ctx)},Kt=function(t,e,r){return P(t,r),T(t,-2),d(t,2,1,r,Ft),Ft(t,p,r)},Ft=function(t,e,r){var n=r;return b(t,-1)||F(t,2,n),g(t,2,n)==h&&(m(t,1),C(t,-1),F(t,2,n)),1},jt={loadlib:function(t){var e=et(t,1),r=et(t,2),n=mt(t,e,r);return 0===n?1:(M(t),T(t,-2),w(t,1===n?"open":"init"),3)},searchpath:function(t){return null!==wt(t,et(t,1),et(t,2),lt(t,3,"."),lt(t,4,s))?1:(M(t),T(t,-2),2)}},Ht={require:function(t){var e=et(t,1);return H(t,1),g(t,v,q),g(t,2,e),X(t,-1)?1:(E(t,1),function(t,e,r,n){var a=new Q;return tt(t,a),g(t,J(1),ht("searchers",!0))!==L&&rt(t,ht("'package.searchers' must be a table")),Gt(t,p,{name:e,i:1,msg:a,ctx:r,k:n})}(t,e,e,Kt))}};t.exports.luaopen_package=function(t){return function(t){O(t),A(t,0,1),j(t,-2),G(t,v,gt)}(t),ot(t,jt),function(t){var e=[Bt,Pt,Dt,Vt,null];A(t);for(var r=0;e[r];r++)C(t,-2),U(t,e[r],1),B(t,-2,r+1);F(t,-2,ht("searchers",!0))}(t),Nt(t,ht("path",!0),"LUA_PATH",i),Nt(t,ht("jspath",!0),"LUA_JSPATH",l),w(t,s+"\n"+f+"\n"+c+"\n"+o+"\n-\n"),F(t,-2,ht("config",!0)),nt(t,v,q),F(t,-2,ht("loaded",!0)),nt(t,v,W),F(t,-2,ht("preload",!0)),y(t),C(t,-2),ct(t,Ht,1),E(t,1),1}},function(t,e,r){var n=r(2),a=n.lua_pushinteger,u=n.lua_pushliteral,s=n.lua_setfield,o=r(7).luaL_newlib,l=r(5),i=l.FENGARI_AUTHORS,c=l.FENGARI_COPYRIGHT,f=l.FENGARI_RELEASE,_=l.FENGARI_VERSION,p=l.FENGARI_VERSION_MAJOR,v=l.FENGARI_VERSION_MINOR,h=l.FENGARI_VERSION_NUM,L=l.FENGARI_VERSION_RELEASE,d=l.to_luastring;t.exports.luaopen_fengari=function(t){return o(t,{}),u(t,i),s(t,-2,d("AUTHORS")),u(t,c),s(t,-2,d("COPYRIGHT")),u(t,f),s(t,-2,d("RELEASE")),u(t,_),s(t,-2,d("VERSION")),u(t,p),s(t,-2,d("VERSION_MAJOR")),u(t,v),s(t,-2,d("VERSION_MINOR")),a(t,h),s(t,-2,d("VERSION_NUM")),u(t,L),s(t,-2,d("VERSION_RELEASE")),1}},function(t,e,r){"use strict";r.r(e),r.d(e,"L",function(){return R}),r.d(e,"load",function(){return y});var n=r(0);r.d(e,"FENGARI_AUTHORS",function(){return n.FENGARI_AUTHORS}),r.d(e,"FENGARI_COPYRIGHT",function(){return n.FENGARI_COPYRIGHT}),r.d(e,"FENGARI_RELEASE",function(){return n.FENGARI_RELEASE}),r.d(e,"FENGARI_VERSION",function(){return n.FENGARI_VERSION}),r.d(e,"FENGARI_VERSION_MAJOR",function(){return n.FENGARI_VERSION_MAJOR}),r.d(e,"FENGARI_VERSION_MINOR",function(){return n.FENGARI_VERSION_MINOR}),r.d(e,"FENGARI_VERSION_NUM",function(){return n.FENGARI_VERSION_NUM}),r.d(e,"FENGARI_VERSION_RELEASE",function(){return n.FENGARI_VERSION_RELEASE}),r.d(e,"luastring_eq",function(){return n.luastring_eq}),r.d(e,"luastring_indexOf",function(){return n.luastring_indexOf}),r.d(e,"luastring_of",function(){return n.luastring_of}),r.d(e,"to_jsstring",function(){return n.to_jsstring}),r.d(e,"to_luastring",function(){return n.to_luastring}),r.d(e,"to_uristring",function(){return n.to_uristring}),r.d(e,"lua",function(){return n.lua}),r.d(e,"lauxlib",function(){return n.lauxlib}),r.d(e,"lualib",function(){return n.lualib});var a=r(18);r.d(e,"interop",function(){return a});var u=n.lua.LUA_ERRRUN,s=n.lua.LUA_ERRSYNTAX,o=n.lua.LUA_OK,l=n.lua.LUA_VERSION_MAJOR,i=n.lua.LUA_VERSION_MINOR,c=n.lua.lua_Debug,f=n.lua.lua_getinfo,_=n.lua.lua_getstack,p=n.lua.lua_gettop,v=n.lua.lua_insert,h=n.lua.lua_pcall,L=n.lua.lua_pop,d=n.lua.lua_pushcfunction,A=n.lua.lua_pushstring,g=n.lua.lua_remove,T=n.lua.lua_setglobal,x=n.lua.lua_tojsstring,b=n.lauxlib.luaL_loadbuffer,k=n.lauxlib.luaL_newstate,O=n.lauxlib.luaL_requiref,E=a.checkjs,m=a.luaopen_js,U=a.push,N=a.tojs,R=k();function y(t,e){if("string"==typeof t)t=Object(n.to_luastring)(t);else if(!(t instanceof Uint8Array))throw new TypeError("expects an array of bytes or javascript string");e=e?Object(n.to_luastring)(e):null;var r,a=b(R,t,null,e);if(r=a===s?new SyntaxError(x(R,-1)):N(R,-1),L(R,1),a!==o)throw r;return r}if(n.lualib.luaL_openlibs(R),O(R,Object(n.to_luastring)("js"),m,1),L(R,1),A(R,Object(n.to_luastring)(n.FENGARI_COPYRIGHT)),T(R,Object(n.to_luastring)("_COPYRIGHT")),"undefined"!=typeof document&&document instanceof HTMLDocument){var S=function(t){var e=new c;return _(t,2,e)&&f(t,Object(n.to_luastring)("Sl"),e),U(t,new ErrorEvent("error",{bubbles:!0,cancelable:!0,message:x(t,1),error:N(t,1),filename:e.short_src?Object(n.to_jsstring)(e.short_src):void 0,lineno:e.currentline>0?e.currentline:void 0})),1},w=function(t,e,r){var n,a=b(R,e,null,r);if(a===s){var l=x(R,-1),i=t.src?t.src:document.location,c=new SyntaxError(l,i,void 0);n=new ErrorEvent("error",{message:l,error:c,filename:i,lineno:void 0})}else if(a===o){var f=p(R);d(R,S),v(R,f),Object.defineProperty(document,"currentScript",{value:t,configurable:!0}),a=h(R,0,0,f),delete document.currentScript,g(R,f),a===u&&(n=E(R,-1))}a!==o&&(void 0===n&&(n=new ErrorEvent("error",{message:x(R,-1),error:N(R,-1)})),L(R,1),window.dispatchEvent(n)&&console.error("uncaught exception",n.error))},I=function(t,e,r){if(t.status>=200&&t.status<300){var a=t.response;a="string"==typeof a?Object(n.to_luastring)(t.response):new Uint8Array(a),w(e,a,r)}else e.dispatchEvent(new Event("error"))},M=/^(.*?\/.*?)([\t ]*;.*)?$/,P=/^(\d+)\.(\d+)$/,C=function(t){if("SCRIPT"===t.tagName){var e=M.exec(t.type);if(e){var r=e[1];if("application/lua"===r||"text/lua"===r){if(t.hasAttribute("lua-version")){var a=P.exec(t.getAttribute("lua-version"));if(!a||a[1]!==l||a[2]!==i)return}!function(t){if(t.src){var e=Object(n.to_luastring)("@"+t.src);if("complete"===document.readyState||t.async)if("function"==typeof fetch)fetch(t.src,{method:"GET",credentials:function(t){switch(t){case"anonymous":return"omit";case"use-credentials":return"include";default:return"same-origin"}}(t.crossorigin),redirect:"follow",integrity:t.integrity}).then(function(t){if(t.ok)return t.arrayBuffer();throw new Error("unable to fetch")}).then(function(r){var n=new Uint8Array(r);w(t,n,e)}).catch(function(e){t.dispatchEvent(new Event("error"))});else{var r=new XMLHttpRequest;r.open("GET",t.src,!0),r.responseType="arraybuffer",r.onreadystatechange=function(){4===r.readyState&&I(r,t,e)},r.send()}else{var a=new XMLHttpRequest;a.open("GET",t.src,!1),a.send(),I(a,t,e)}}else{var u=Object(n.to_luastring)(t.innerHTML),s=t.id?Object(n.to_luastring)("="+t.id):u;w(t,u,s)}}(t)}}}};"undefined"!=typeof MutationObserver?new MutationObserver(function(t,e){for(var r=0;rt.lasttarget&&(n=t.f.code[t.pc-1]).opcode===w.OP_LOADNIL){var u=n.A,s=u+n.B;if(u<=e&&e<=s+1||e<=u&&u<=a+1)return ua&&(a=s),N.SETARG_A(n,e),void N.SETARG_B(n,a-e)}tt(t,w.OP_LOADNIL,e,r-1,0)},B=function(t,e){return t.f.code[e.u.info]},G=function(t,e){var r=t.f.code[e].sBx;return-1===r?-1:e+1+r},K=function(t,e,r){var n=t.f.code[e],a=r-(e+1);E(-1!==r),Math.abs(a)>N.MAXARG_sBx&&m.luaX_syntaxerror(t.ls,O("control structure too long",!0)),N.SETARG_sBx(n,a)},F=function(t,e,r){if(-1===r)return e;if(-1===e)e=r;else{for(var n=e,a=G(t,n);-1!==a;)a=G(t,n=a);K(t,n,r)}return e},j=function(t){var e=t.jpc;t.jpc=-1;var r=rt(t,w.OP_JMP,0,-1);return r=F(t,r,e)},H=function(t,e,r,n,a){return tt(t,e,r,n,a),j(t)},X=function(t){return t.lasttarget=t.pc,t.pc},z=function(t,e){return e>=1&&N.testTMode(t.f.code[e-1].opcode)?e-1:e},Y=function(t,e){return t.f.code[z(t,e)]},J=function(t,e,r){var n=z(t,e),a=t.f.code[n];return a.opcode===w.OP_TESTSET&&(r!==N.NO_REG&&r!==a.B?N.SETARG_A(a,r):t.f.code[n]=N.CREATE_ABC(w.OP_TEST,a.B,0,a.C),!0)},Z=function(t,e){for(;-1!==e;e=G(t,e))J(t,e,N.NO_REG)},q=function(t,e,r,n,a){for(;-1!==e;){var u=G(t,e);J(t,e,n)?K(t,e,r):K(t,e,a),e=u}},W=function(t,e){X(t),t.jpc=F(t,t.jpc,e)},Q=function(t,e,r){r===t.pc?W(t,e):(E(rt.f.maxstacksize&&(r>=255&&m.luaX_syntaxerror(t.ls,O("function or expression needs too many registers",!0)),t.f.maxstacksize=r)},st=function(t,e){ut(t,e),t.freereg+=e},ot=function(t,e){!N.ISK(e)&&e>=t.nactvar&&(t.freereg--,E(e===t.freereg))},lt=function(t,e){e.k===R.expkind.VNONRELOC&&ot(t,e.u.info)},it=function(t,e,r){var n=e.k===R.expkind.VNONRELOC?e.u.info:-1,a=r.k===R.expkind.VNONRELOC?r.u.info:-1;n>a?(ot(t,n),ot(t,a)):(ot(t,a),ot(t,n))},ct=function(t,e,r){var n=t.f,a=y.luaH_get(t.L,t.ls.h,e);if(a.ttisinteger()){var u=a.value;if(u=t.nactvar)return xt(t,e,e.u.info),e.u.info}return bt(t,e),e.u.info},Ot=function(t,e){C(e)?kt(t,e):Lt(t,e)},Et=function(t,e){var r=R.expkind,n=!1;switch(Ot(t,e),e.k){case r.VTRUE:e.u.info=pt(t,!0),n=!0;break;case r.VFALSE:e.u.info=pt(t,!1),n=!0;break;case r.VNIL:e.u.info=function(t){var e=new I(T,null),r=new I(k,t.ls.h);return ct(t,r,e)}(t),n=!0;break;case r.VKINT:e.u.info=ft(t,e.u.ival),n=!0;break;case r.VKFLT:e.u.info=_t(t,e.u.nval),n=!0;break;case r.VK:n=!0}return n&&(e.k=r.VK,e.u.info<=N.MAXINDEXRK)?N.RKASK(e.u.info):kt(t,e)},mt=function(t,e){var r=Y(t,e.u.info);E(N.testTMode(r.opcode)&&r.opcode!==w.OP_TESTSET&&r.opcode!==w.OP_TEST),N.SETARG_A(r,!r.A)},Ut=function(t,e,r){if(e.k===R.expkind.VRELOCABLE){var n=B(t,e);if(n.opcode===w.OP_NOT)return t.pc--,H(t,w.OP_TEST,n.B,0,!r)}return gt(t,e),lt(t,e),H(t,w.OP_TESTSET,N.NO_REG,e.u.info,r)},Nt=function(t,e){var r,n=R.expkind;switch(Lt(t,e),e.k){case n.VJMP:mt(t,e),r=e.u.info;break;case n.VK:case n.VKFLT:case n.VKINT:case n.VTRUE:r=-1;break;default:r=Ut(t,e,0)}e.f=F(t,e.f,r),W(t,e.t),e.t=-1},Rt=function(t,e){var r,n=R.expkind;switch(Lt(t,e),e.k){case n.VJMP:r=e.u.info;break;case n.VNIL:case n.VFALSE:r=-1;break;default:r=Ut(t,e,1)}e.t=F(t,e.t,r),W(t,e.f),e.f=-1},yt=function(t,e,r){var n,a,u=R.expkind;if(!(n=D(e,!0))||!(a=D(r,!0))||!function(t,e,r){switch(t){case s:case l:case i:case p:case v:case o:return!1!==S.tointeger(e)&&!1!==S.tointeger(r);case c:case f:case _:return 0!==r.value;default:return 1}}(t,n,a))return 0;var h=new I;if(U.luaO_arith(null,t,n,a,h),h.ttisinteger())e.k=u.VKINT,e.u.ival=h.value;else{var L=h.value;if(isNaN(L)||0===L)return!1;e.k=u.VKFLT,e.u.nval=L}return!0},St=function(t,e,r,n,a){var u=Et(t,n),s=Et(t,r);it(t,r,n),r.u.info=tt(t,e,0,s,u),r.k=R.expkind.VRELOCABLE,wt(t,a)},wt=function(t,e){t.f.lineinfo[t.pc-1]=e};t.exports.BinOpr=M,t.exports.NO_JUMP=-1,t.exports.UnOpr=P,t.exports.getinstruction=B,t.exports.luaK_checkstack=ut,t.exports.luaK_code=$,t.exports.luaK_codeABC=tt,t.exports.luaK_codeABx=et,t.exports.luaK_codeAsBx=rt,t.exports.luaK_codek=at,t.exports.luaK_concat=F,t.exports.luaK_dischargevars=Lt,t.exports.luaK_exp2RK=Et,t.exports.luaK_exp2anyreg=kt,t.exports.luaK_exp2anyregup=function(t,e){(e.k!==R.expkind.VUPVAL||C(e))&&kt(t,e)},t.exports.luaK_exp2nextreg=bt,t.exports.luaK_exp2val=Ot,t.exports.luaK_fixline=wt,t.exports.luaK_getlabel=X,t.exports.luaK_goiffalse=Rt,t.exports.luaK_goiftrue=Nt,t.exports.luaK_indexed=function(t,e,r){var n=R.expkind;E(!C(e)&&(R.vkisinreg(e.k)||e.k===n.VUPVAL)),e.u.ind.t=e.u.info,e.u.ind.idx=Et(t,r),e.u.ind.vt=e.k===n.VUPVAL?n.VUPVAL:n.VLOCAL,e.k=n.VINDEXED},t.exports.luaK_infix=function(t,e,r){switch(e){case M.OPR_AND:Nt(t,r);break;case M.OPR_OR:Rt(t,r);break;case M.OPR_CONCAT:bt(t,r);break;case M.OPR_ADD:case M.OPR_SUB:case M.OPR_MUL:case M.OPR_DIV:case M.OPR_IDIV:case M.OPR_MOD:case M.OPR_POW:case M.OPR_BAND:case M.OPR_BOR:case M.OPR_BXOR:case M.OPR_SHL:case M.OPR_SHR:D(r,!1)||Et(t,r);break;default:Et(t,r)}},t.exports.luaK_intK=ft,t.exports.luaK_jump=j,t.exports.luaK_jumpto=function(t,e){return Q(t,j(t),e)},t.exports.luaK_nil=V,t.exports.luaK_numberK=_t,t.exports.luaK_patchclose=function(t,e,r){for(r++;-1!==e;e=G(t,e)){var n=t.f.code[e];E(n.opcode===w.OP_JMP&&(0===n.A||n.A>=r)),N.SETARG_A(n,r)}},t.exports.luaK_patchlist=Q,t.exports.luaK_patchtohere=W,t.exports.luaK_posfix=function(t,e,r,n,a){var s=R.expkind;switch(e){case M.OPR_AND:E(-1===r.t),Lt(t,n),n.f=F(t,n.f,r.f),r.to(n);break;case M.OPR_OR:E(-1===r.f),Lt(t,n),n.t=F(t,n.t,r.t),r.to(n);break;case M.OPR_CONCAT:Ot(t,n);var o=B(t,n);n.k===s.VRELOCABLE&&o.opcode===w.OP_CONCAT?(E(r.u.info===o.B-1),lt(t,r),N.SETARG_B(o,r.u.info),r.k=s.VRELOCABLE,r.u.info=n.u.info):(bt(t,n),St(t,w.OP_CONCAT,r,n,a));break;case M.OPR_ADD:case M.OPR_SUB:case M.OPR_MUL:case M.OPR_DIV:case M.OPR_IDIV:case M.OPR_MOD:case M.OPR_POW:case M.OPR_BAND:case M.OPR_BOR:case M.OPR_BXOR:case M.OPR_SHL:case M.OPR_SHR:yt(e+u,r,n)||St(t,e+w.OP_ADD,r,n,a);break;case M.OPR_EQ:case M.OPR_LT:case M.OPR_LE:case M.OPR_NE:case M.OPR_GT:case M.OPR_GE:!function(t,e,r,n){var a,u=R.expkind;r.k===u.VK?a=N.RKASK(r.u.info):(E(r.k===u.VNONRELOC),a=r.u.info);var s=Et(t,n);switch(it(t,r,n),e){case M.OPR_NE:r.u.info=H(t,w.OP_EQ,0,a,s);break;case M.OPR_GT:case M.OPR_GE:var o=e-M.OPR_NE+w.OP_EQ;r.u.info=H(t,o,1,s,a);break;default:var l=e-M.OPR_EQ+w.OP_EQ;r.u.info=H(t,l,1,a,s)}r.k=u.VJMP}(t,e,r,n)}return r},t.exports.luaK_prefix=function(t,e,r,n){var a=new R.expdesc;switch(a.k=R.expkind.VKINT,a.u.ival=a.u.nval=a.u.info=0,a.t=-1,a.f=-1,e){case P.OPR_MINUS:case P.OPR_BNOT:if(yt(e+h,r,a))break;case P.OPR_LEN:!function(t,e,r,n){var a=kt(t,r);lt(t,r),r.u.info=tt(t,e,0,a,0),r.k=R.expkind.VRELOCABLE,wt(t,n)}(t,e+w.OP_UNM,r,n);break;case P.OPR_NOT:!function(t,e){var r=R.expkind;switch(Lt(t,e),e.k){case r.VNIL:case r.VFALSE:e.k=r.VTRUE;break;case r.VK:case r.VKFLT:case r.VKINT:case r.VTRUE:e.k=r.VFALSE;break;case r.VJMP:mt(t,e);break;case r.VRELOCABLE:case r.VNONRELOC:gt(t,e),lt(t,e),e.u.info=tt(t,w.OP_NOT,0,e.u.info,0),e.k=r.VRELOCABLE}var n=e.f;e.f=e.t,e.t=n,Z(t,e.f),Z(t,e.t)}(t,r)}},t.exports.luaK_reserveregs=st,t.exports.luaK_ret=function(t,e,r){tt(t,w.OP_RETURN,e,r+1,0)},t.exports.luaK_self=function(t,e,r){kt(t,e);var n=e.u.info;lt(t,e),e.u.info=t.freereg,e.k=R.expkind.VNONRELOC,st(t,2),tt(t,w.OP_SELF,e.u.info,n,Et(t,r)),lt(t,r)},t.exports.luaK_setlist=function(t,e,r,n){var u=(r-1)/N.LFIELDS_PER_FLUSH+1,s=n===a?0:n;E(0!==n&&n<=N.LFIELDS_PER_FLUSH),u<=N.MAXARG_C?tt(t,w.OP_SETLIST,e,s,u):u<=N.MAXARG_Ax?(tt(t,w.OP_SETLIST,e,s,0),nt(t,u)):m.luaX_syntaxerror(t.ls,O("constructor too long",!0)),t.freereg=e+1},t.exports.luaK_setmultret=function(t,e){vt(t,e,a)},t.exports.luaK_setoneret=ht,t.exports.luaK_setreturns=vt,t.exports.luaK_storevar=function(t,e,r){var n=R.expkind;switch(e.k){case n.VLOCAL:return lt(t,r),void xt(t,r,e.u.info);case n.VUPVAL:var a=kt(t,r);tt(t,w.OP_SETUPVAL,a,e.u.info,0);break;case n.VINDEXED:var u=e.u.ind.vt===n.VLOCAL?w.OP_SETTABLE:w.OP_SETTABUP,s=Et(t,r);tt(t,u,e.u.ind.t,e.u.ind.idx,s)}lt(t,r)},t.exports.luaK_stringK=function(t,e){var r=new I(g,e);return ct(t,r,r)}},function(t,e,r){"use strict";function n(t,e){for(var r=0;r>U&n.MASK1(I,0),A:u>>b&n.MASK1(N,0),B:u>>O&n.MASK1(y,0),C:u>>m&n.MASK1(w,0),Bx:u>>E&n.MASK1(S,0),Ax:u>>k&n.MASK1(R,0),sBx:(u>>E&n.MASK1(S,0))-x}}}},{key:"LoadConstants",value:function(t){for(var e=this.LoadInt(),r=0;r0&&(r.status=r.writer(r.L,t,e,r.data))},g=function(t,e){A(v(t),1,e)},T=function(t,e){var r=new ArrayBuffer(4);new DataView(r).setInt32(0,t,!0);var n=new Uint8Array(r);A(n,4,e)},x=function(t,e){var r=new ArrayBuffer(4);new DataView(r).setInt32(0,t,!0);var n=new Uint8Array(r);A(n,4,e)},b=function(t,e){var r=new ArrayBuffer(8);new DataView(r).setFloat64(0,t,!0);var n=new Uint8Array(r);A(n,8,e)},k=function(t,e){if(null===t)g(0,e);else{var r=t.tsslen()+1,n=t.getstr();r<255?g(r,e):(g(255,e),x(r,e)),A(n,r-1,e)}},O=function(t,e){var r=t.p.length;T(r,e);for(var n=0;n=0),o[8]){case"b":r=parseInt(r,10).toString(2);break;case"c":r=String.fromCharCode(parseInt(r,10));break;case"d":case"i":r=parseInt(r,10);break;case"j":r=JSON.stringify(r,null,o[6]?parseInt(o[6]):0);break;case"e":r=o[7]?parseFloat(r).toExponential(o[7]):parseFloat(r).toExponential();break;case"f":r=o[7]?parseFloat(r).toFixed(o[7]):parseFloat(r);break;case"g":r=o[7]?String(Number(r.toPrecision(o[7]))):parseFloat(r);break;case"o":r=(parseInt(r,10)>>>0).toString(8);break;case"s":r=String(r),r=o[7]?r.substring(0,o[7]):r;break;case"t":r=String(!!r),r=o[7]?r.substring(0,o[7]):r;break;case"T":r=Object.prototype.toString.call(r).slice(8,-1).toLowerCase(),r=o[7]?r.substring(0,o[7]):r;break;case"u":r=parseInt(r,10)>>>0;break;case"v":r=r.valueOf(),r=o[7]?r.substring(0,o[7]):r;break;case"x":r=(parseInt(r,10)>>>0).toString(16);break;case"X":r=(parseInt(r,10)>>>0).toString(16).toUpperCase()}a.json.test(o[8])?h+=r:(!a.number.test(o[8])||f&&!o[3]?_="":(_=f?"+":"-",r=r.toString().replace(a.sign,"")),i=o[4]?"0"===o[4]?"0":o[4].charAt(1):" ",c=o[6]-(_+r).length,l=o[6]&&c>0?i.repeat(c):"",h+=o[5]?_+r+l:"0"===i?_+l+r:l+_+r)}return h}(function(t){if(o[t])return o[t];var e,r=t,n=[],u=0;for(;r;){if(null!==(e=a.text.exec(r)))n.push(e[0]);else if(null!==(e=a.modulo.exec(r)))n.push("%");else{if(null===(e=a.placeholder.exec(r)))throw new SyntaxError("[sprintf] unexpected placeholder");if(e[2]){u|=1;var s=[],l=e[2],i=[];if(null===(i=a.key.exec(l)))throw new SyntaxError("[sprintf] failed to parse named argument key");for(s.push(i[1]);""!==(l=l.substring(i[0].length));)if(null!==(i=a.key_access.exec(l)))s.push(i[1]);else{if(null===(i=a.index_access.exec(l)))throw new SyntaxError("[sprintf] failed to parse named argument key");s.push(i[1])}e[2]=s}else u|=2;if(3===u)throw new Error("[sprintf] mixing positional and named placeholders is not (yet) supported");n.push(e)}r=r.substring(e[0].length)}return o[t]=n}(t),arguments)}function s(t,e){return u.apply(null,[t].concat(e||[]))}var o=Object.create(null);e.sprintf=u,e.vsprintf=s,"undefined"!=typeof window&&(window.sprintf=u,window.vsprintf=s,void 0===(n=function(){return{sprintf:u,vsprintf:s}}.call(e,r,e,t))||(t.exports=n))}()},function(t,e,r){"use strict";var n=r(2).lua_pop,a=r(7).luaL_requiref,u=r(5).to_luastring,s={};t.exports.luaL_openlibs=function(t){for(var e in s)a(t,u(e),s[e],1),n(t,1)};var o=r(17),l=r(24).luaopen_base,i=r(25).luaopen_coroutine,c=r(31).luaopen_debug,f=r(30).luaopen_math,_=r(32).luaopen_package,p=r(27).luaopen_os,v=r(28).luaopen_string,h=r(26).luaopen_table,L=r(29).luaopen_utf8;s._G=l,s[o.LUA_LOADLIBNAME]=_,s[o.LUA_COLIBNAME]=i,s[o.LUA_TABLIBNAME]=h,s[o.LUA_OSLIBNAME]=p,s[o.LUA_STRLIBNAME]=v,s[o.LUA_MATHLIBNAME]=f,s[o.LUA_UTF8LIBNAME]=L,s[o.LUA_DBLIBNAME]=c;var d=r(33).luaopen_fengari;s[o.LUA_FENGARILIBNAME]=d}])}); \ No newline at end of file diff --git a/root/static/fengari-web/map: application$json b/root/static/fengari-web/map: application$json new file mode 100644 index 0000000..1fa13e2 --- /dev/null +++ b/root/static/fengari-web/map: application$json @@ -0,0 +1 @@ +{"version":3,"sources":["webpack://fengari/webpack/universalModuleDefinition","webpack://fengari/webpack/bootstrap","webpack://fengari/./node_modules/fengari/src/fengari.js","webpack://fengari/./node_modules/fengari/src/defs.js","webpack://fengari/./node_modules/fengari/src/lua.js","webpack://fengari/./node_modules/fengari/src/luaconf.js","webpack://fengari/./node_modules/fengari/src/llimits.js","webpack://fengari/./node_modules/fengari/src/fengaricore.js","webpack://fengari/./node_modules/fengari/src/lobject.js","webpack://fengari/./node_modules/fengari/src/lauxlib.js","webpack://fengari/./node_modules/fengari/src/ldo.js","webpack://fengari/./node_modules/fengari/src/ltable.js","webpack://fengari/./node_modules/fengari/src/lstring.js","webpack://fengari/./node_modules/fengari/src/ldebug.js","webpack://fengari/./node_modules/fengari/src/lstate.js","webpack://fengari/./node_modules/fengari/src/lfunc.js","webpack://fengari/./node_modules/fengari/src/ltm.js","webpack://fengari/./node_modules/fengari/src/lvm.js","webpack://fengari/./node_modules/fengari/src/lopcodes.js","webpack://fengari/./node_modules/fengari/src/lualib.js","webpack://fengari/./node_modules/fengari-interop/src/js.js","webpack://fengari/./node_modules/fengari/src/lapi.js","webpack://fengari/./node_modules/fengari/src/lzio.js","webpack://fengari/./node_modules/fengari/src/llex.js","webpack://fengari/./node_modules/fengari/src/ljstype.js","webpack://fengari/./node_modules/fengari/src/lparser.js","webpack://fengari/./node_modules/fengari/src/lbaselib.js","webpack://fengari/./node_modules/fengari/src/lcorolib.js","webpack://fengari/./node_modules/fengari/src/ltablib.js","webpack://fengari/./node_modules/fengari/src/loslib.js","webpack://fengari/./node_modules/fengari/src/lstrlib.js","webpack://fengari/./node_modules/fengari/src/lutf8lib.js","webpack://fengari/./node_modules/fengari/src/lmathlib.js","webpack://fengari/./node_modules/fengari/src/ldblib.js","webpack://fengari/./node_modules/fengari/src/loadlib.js","webpack://fengari/./node_modules/fengari/src/fengarilib.js","webpack://fengari/./src/fengari-web.js","webpack://fengari/./node_modules/fengari/src/lcode.js","webpack://fengari/./node_modules/fengari/src/lundump.js","webpack://fengari/./node_modules/fengari/src/ldump.js","webpack://fengari/./node_modules/sprintf-js/src/sprintf.js","webpack://fengari/./node_modules/fengari/src/linit.js"],"names":["root","factory","exports","module","define","amd","window","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","core","require","FENGARI_AUTHORS","FENGARI_COPYRIGHT","FENGARI_RELEASE","FENGARI_VERSION","FENGARI_VERSION_MAJOR","FENGARI_VERSION_MINOR","FENGARI_VERSION_NUM","FENGARI_VERSION_RELEASE","luastring_eq","luastring_indexOf","luastring_of","to_jsstring","to_luastring","to_uristring","luaconf","lua","lauxlib","lualib","luastring_from","Uint8Array","from","a","len","length","indexOf","v","array_indexOf","Error","of","arguments","is_luastring","unicode_error_message","uri_allowed","split","reduce","charCodeAt","to_luastring_cache","str","cache","TypeError","cached","outU8Array","Array","outIdx","u","b","to","replacement_char","Math","min","u0","String","fromCharCode","RangeError","u1","u2","s1","s2","u3","toString","from_userstring","LUA_SIGNATURE","LUA_VERSION_MAJOR","LUA_VERSION_MINOR","LUA_VERSION_NUM","LUA_VERSION_RELEASE","LUA_VERSION","LUA_RELEASE","LUA_COPYRIGHT","LUA_AUTHORS","constant_types","LUA_TNONE","LUA_TNIL","LUA_TBOOLEAN","LUA_TLIGHTUSERDATA","LUA_TNUMBER","LUA_TSTRING","LUA_TTABLE","LUA_TFUNCTION","LUA_TUSERDATA","LUA_TTHREAD","LUA_NUMTAGS","LUA_TSHRSTR","LUA_TLNGSTR","LUA_TNUMFLT","LUA_TNUMINT","LUA_TLCL","LUA_TLCF","LUA_TCCL","LUA_REGISTRYINDEX","LUAI_MAXSTACK","LUA_HOOKCALL","LUA_HOOKCOUNT","LUA_HOOKLINE","LUA_HOOKRET","LUA_HOOKTAILCALL","LUA_MASKCALL","LUA_MASKCOUNT","LUA_MASKLINE","LUA_MASKRET","LUA_MINSTACK","LUA_MULTRET","LUA_OPADD","LUA_OPBAND","LUA_OPBNOT","LUA_OPBOR","LUA_OPBXOR","LUA_OPDIV","LUA_OPEQ","LUA_OPIDIV","LUA_OPLE","LUA_OPLT","LUA_OPMOD","LUA_OPMUL","LUA_OPPOW","LUA_OPSHL","LUA_OPSHR","LUA_OPSUB","LUA_OPUNM","LUA_RIDX_GLOBALS","LUA_RIDX_LAST","LUA_RIDX_MAINTHREAD","lua_Debug","_classCallCheck","this","event","NaN","namewhat","what","source","currentline","linedefined","lastlinedefined","nups","nparams","isvararg","istailcall","short_src","i_ci","lua_upvalueindex","thread_status","LUA_OK","LUA_YIELD","LUA_ERRRUN","LUA_ERRSYNTAX","LUA_ERRMEM","LUA_ERRGCMM","LUA_ERRERR","defs","lapi","ldebug","ldo","lstate","lua_absindex","lua_arith","lua_atpanic","lua_atnativeerror","lua_call","lua_callk","lua_checkstack","lua_close","lua_compare","lua_concat","lua_copy","lua_createtable","lua_dump","lua_error","lua_gc","lua_getallocf","lua_getextraspace","lua_getfield","lua_getglobal","lua_gethook","lua_gethookcount","lua_gethookmask","lua_geti","lua_getinfo","lua_getlocal","lua_getmetatable","lua_getstack","lua_gettable","lua_gettop","lua_getupvalue","lua_getuservalue","lua_insert","lua_isboolean","lua_iscfunction","lua_isfunction","lua_isinteger","lua_islightuserdata","lua_isnil","lua_isnone","lua_isnoneornil","lua_isnumber","lua_isproxy","lua_isstring","lua_istable","lua_isthread","lua_isuserdata","lua_isyieldable","lua_len","lua_load","lua_newstate","lua_newtable","lua_newthread","lua_newuserdata","lua_next","lua_pcall","lua_pcallk","lua_pop","lua_pushboolean","lua_pushcclosure","lua_pushcfunction","lua_pushfstring","lua_pushglobaltable","lua_pushinteger","lua_pushjsclosure","lua_pushjsfunction","lua_pushlightuserdata","lua_pushliteral","lua_pushlstring","lua_pushnil","lua_pushnumber","lua_pushstring","lua_pushthread","lua_pushvalue","lua_pushvfstring","lua_rawequal","lua_rawget","lua_rawgeti","lua_rawgetp","lua_rawlen","lua_rawset","lua_rawseti","lua_rawsetp","lua_register","lua_remove","lua_replace","lua_resume","lua_rotate","lua_setallof","lua_setfield","lua_setglobal","lua_sethook","lua_seti","lua_setlocal","lua_setmetatable","lua_settable","lua_settop","lua_setupvalue","lua_setuservalue","lua_status","lua_stringtonumber","lua_toboolean","lua_todataview","lua_tointeger","lua_tointegerx","lua_tojsstring","lua_tolstring","lua_tonumber","lua_tonumberx","lua_topointer","lua_toproxy","lua_tostring","lua_tothread","lua_touserdata","lua_type","lua_typename","lua_upvalueid","lua_upvaluejoin","lua_version","lua_xmove","lua_yield","lua_yieldk","lua_tocfunction","conf","LUA_PATH_SEP","LUA_PATH_MARK","LUA_EXEC_DIR","LUA_VDIR","LUA_DIRSEP","LUA_LDIR","LUA_JSDIR","LUA_PATH_DEFAULT","LUA_JSPATH_DEFAULT","LUA_COMPAT_FLOATSTRING","LUA_IDSIZE","LUA_INTEGER_FMT","concat","LUAL_BUFFERSIZE","ldexp","mantissa","exponent","steps","ceil","abs","result","pow","floor","LUA_INTEGER_FRMLEN","LUA_MAXINTEGER","LUA_MININTEGER","LUA_NUMBER_FMT","LUA_NUMBER_FRMLEN","frexp","data","DataView","ArrayBuffer","setFloat64","bits","getUint32","lua_getlocaledecpoint","lua_integer2str","lua_number2str","Number","toPrecision","lua_numbertointeger","luai_apicheck","e","lua_assert","api_check","msg","LUAI_MAXCCALLS","LUA_MINBUFFER","luai_nummod","L","MAX_INT","MIN_INT","lisdigit","lisprint","lisspace","lisxdigit","luaS_bless","luaS_new","ltable","lvm","ltm","LUA_TPROTO","LUA_TDEADKEY","TValue","type","ttnov","checktype","checktag","ttisnil","ttisboolean","x","tv","ttisstring","tsvalue","getstr","tsslen","svalue","setsvalue2s","newidx","ts","stack","setsvalue","luaO_nilobject","freeze","LClosure","id","l_G","id_counter","nupvalues","upvals","CClosure","f","upvalue","Udata","size","metatable","uservalue","RETS","PRE","POS","luaO_hexavalue","luaO_utf8esc","buff","UTF8BUFFSZ","mfb","l_str2dloc","neg","sigdig","nosigdig","hasdot","neg1","exp1","lua_strx2number","exec","flt","parseFloat","isNaN","lua_str2number","SIGILS","modes","_defineProperty","_modes","MAXBY10","MAXLASTD","luaO_tostring","obj","ttisinteger","test","pushstr","luaD_inctop","top","luaO_pushvfstring","fmt","argp","subarray","luaO_pushfstring","setivalue","setfltvalue","lua_State","Table","_typeof","JSON","stringify","ids","set","luaG_runerror","luaD_checkstack","luaV_concat","_len","_key","intarith","op","v1","v2","luaV_imul","luaV_mod","luaV_div","luaV_shiftl","numarith","LocVar","varname","startpc","endpc","luaO_arith","p1","p2","p3","res","i1","i2","tointeger","n1","n2","tonumber","luaT_trybinTM","TMS","TM_ADD","luaO_chunkid","bufflen","out","nli","out_i","luaO_int2fb","luaO_str2num","s2i","empty","l_str2int","pmode","l_str2d","pushobj2s","pushsvalue2s","setobjs2s","oldidx","setfrom","setobj2s","oldtv","getc","luaL_loadfilex","LUA_ERRFILE","LUA_LOADED_TABLE","LUA_PRELOAD_TABLE","LUA_FILEHANDLE","__name","__tostring","luaL_Buffer","pushglobalfuncname","ar","findfield","objidx","level","pushfuncname","panic","luaL_argerror","arg","extramsg","luaL_error","typeerror","tname","typearg","luaL_getmetafield","luaL_typename","luaL_where","luaL_fileresult","stat","fname","message","errno","luaL_getmetatable","luaL_testudata","ud","tag_error","tag","luaL_checklstring","undefined","luaL_checkstring","luaL_optlstring","def","luaL_optstring","luaL_checknumber","luaL_checkinteger","interror","luaL_prepbuffsize","B","sz","newend","newsize","max","newbuff","luaL_buffinit","luaL_addlstring","luaL_addsize","luaL_addstring","luaL_pushresult","luaL_opt","getS","string","luaL_loadbufferx","luaL_loadbuffer","luaL_loadstring","tt","luaL_callmeta","p_I","p_f","find_subarray","arr","subarr","from_index","sl","loop","j","luaL_getsubtable","idx","luaL_setfuncs","nup","lib","luaL_checkstack","space","errfile","fnameindex","error","serr","filename","utf8_bom","skipcomment","lf","skipBOM","skipped","getF","bytes","pos","LoadF","err","path","xhr","XMLHttpRequest","open","responseType","send","status","statusText","response","com","readstatus","luaL_loadfile","luaL_checkversion_","ver","LUA_NOREF","LUA_REFNIL","luaL_addchar","luaL_addvalue","luaL_argcheck","cond","luaL_buffinitsize","luaL_checkany","luaL_checkoption","lst","luaL_checktype","luaL_checkudata","luaL_checkversion","luaL_dofile","luaL_dostring","luaL_execresult","signal","luaL_gsub","wild","luaL_len","luaL_newlib","luaL_newlibtable","luaL_newmetatable","luaL_newstate","luaL_optinteger","luaL_optnumber","luaL_prepbuffer","luaL_pushresultsize","luaL_ref","ref","luaL_requiref","modname","openf","glb","luaL_setmetatable","luaL_tolstring","kind","luaL_traceback","L1","last","li","le","lastlevel","LEVELS1","luaL_unref","lua_writestringerror","console","lfunc","lobject","lopcodes","lparser","luaS_newliteral","lundump","MBuffer","adjust_top","newtop","seterrorobj","errcode","oldtop","current_top","ERRORSTACKSIZE","luaD_reallocstack","stack_last","EXTRA_STACK","luaD_growstack","luaD_throw","needed","luaD_shrinkstack","inuse","lim","ci","previous","stackinuse","goodsize","luaE_freeCI","luaD_precall","off","nresults","func","luaE_extendCI","funcOff","callstatus","hookmask","luaD_hook","api_checknelems","luaD_poscall","base","fsize","maxstacksize","is_vararg","adjust_varargs","numparams","l_base","l_code","code","l_savedpc","CIST_LUA","callhook","tryfuncTM","firstResult","nres","wanted","oldpc","next","moveresults","setnilvalue","line","hook","allowhook","ci_top","CIST_HOOKED","opcode","OpCodesI","OP_TAILCALL","CIST_TAIL","actual","nfixargs","fixed","tm","luaT_gettmbyobj","TM_CALL","ttisfunction","luaG_typeerror","luaD_call","nResults","nCcalls","stackerror","luaV_execute","errorJmp","g","mainthread","luaD_rawrunprotected","oldnCcalls","lj","atnativeerror","luaD_callnoyield","errfunc","e2","finishCcall","c_k","nny","CIST_YPCALL","c_old_errfunc","c_ctx","unroll","base_ci","luaV_finishOp","recover","findpcall","extra","luaF_close","CIST_OAH","resume_error","narg","resume","firstArg","ctx","k","luaD_pcall","old_top","ef","old_ci","old_allowhooks","old_nny","old_errfunc","SParser","z","dyd","Dyndata","checkmode","f_parser","cl","zgetc","luaU_undump","luaY_parser","upvalues","luaF_initupvals","luaD_protectedparser","nargs","oldnny","luaS_hashlongstr","TString","lightuserdata_hashes","WeakMap","get_lightuserdata_hash","hash","table_hash","strong","Map","dead_strong","dead_weak","flags","add","clear","prev","entry","mark_dead","setdeadvalue","delete","is_valid_weakmap_key","getgeneric","luaH_getint","invalidateTMcache","luaH_get","ttisfloat","luaH_getn","luaH_getstr","luaH_setfrom","kv","luaH_setint","luaH_new","luaH_next","table","keyI","keyO","ttisdeadkey","realstring","luaS_hash","luaS_eqlngstr","llex","currentpc","lineinfo","swapextra","temp","upvalname","uv","findlocal","findvararg","luaF_getlocalname","funcinfo","getfuncname","funcname","CIST_FIN","funcnamefromcode","kname","pc","ISK","kvalue","INDEXK","getobjname","filterpc","jmptarget","lastpc","reg","setreg","OCi","A","OP_LOADNIL","OP_TFORCALL","OP_CALL","OP_JMP","dest","sBx","testAMode","findsetreg","OP_MOVE","OP_GETTABUP","OP_GETTABLE","C","vn","LUA_ENV","OP_GETUPVAL","OP_LOADK","OP_LOADKX","Bx","Ax","OP_SELF","TM_INDEX","OP_SETTABUP","OP_SETTABLE","TM_NEWINDEX","OP_ADD","OP_SUB","TM_SUB","OP_MUL","TM_MUL","OP_MOD","TM_MOD","OP_POW","TM_POW","OP_DIV","TM_DIV","OP_IDIV","TM_IDIV","OP_BAND","TM_BAND","OP_BOR","TM_BOR","OP_BXOR","TM_BXOR","OP_SHL","TM_SHL","OP_SHR","TM_SHR","OP_UNM","TM_UNM","OP_BNOT","TM_BNOT","OP_LEN","TM_LEN","OP_CONCAT","TM_CONCAT","OP_EQ","TM_EQ","OP_LT","TM_LT","OP_LE","TM_LE","tmname","varinfo","getupvalname","stkid","isinstack","luaT_objtypename","luaG_addinfo","src","luaG_errormsg","luaG_concaterror","cvt2str","luaG_opinterror","luaG_ordererror","t1","t2","luaG_tointerror","luaG_traceexec","mask","counthook","hookcount","basehookcount","CIST_HOOKYIELD","npc","newline","auxgetinfo","ttisclosure","api_incr_top","collectvalidlines","ttisLclosure","local","count","BASIC_STACK_SIZE","CallInfo","stack_init","freestack","f_luaopen","registry","l_registry","sethvalue","init_registry","luaT_init","version","CIST_FRESH","CIST_LEQ","close_state","global_State","TM_N","mt","luaE_freethread","MAXUPVAL","Proto","locvars","luaF_findupval","old","local_number","luaF_newLclosure","luaT_typenames_","map","ttypename","TM_GC","TM_MODE","luaT_callTM","hasres","luaT_callbinTM","luaT_gettm","events","ename","fasttm","et","luaT_callorderTM","l_isfalse","ttistable","ttisfulluserdata","LFIELDS_PER_FLUSH","OP_CLOSURE","OP_EXTRAARG","OP_FORLOOP","OP_FORPREP","OP_LOADBOOL","OP_NEWTABLE","OP_NOT","OP_RETURN","OP_SETLIST","OP_SETUPVAL","OP_TEST","OP_TESTSET","OP_TFORLOOP","OP_VARARG","RA","RB","RKB","RKC","dojump","donextjump","luaV_lessthan","ttisnumber","LTnum","l_strcmp","luaV_lessequal","LEnum","luaV_equalobj","ttype","forlimit","step","stopnow","ilimit","luaV_tointeger","cvt2num","vslen","ls","rs","luaV_objlen","ra","rb","h","imul","aLo","bLo","y","getcached","encup","instack","pushclosure","ncl","setclLvalue","tostring","isemptystr","copy2buff","tl","total","luaV_gettable","slot","settable","val","newframe","konst","setbvalue","upval","rc","op1","op2","numberop1","numberop2","numberop","rbIdx","nci","oci","nfunc","nfuncOff","ofuncOff","aux","limit","chgivalue","chgfltvalue","init","plimit","pstep","forlim","initv","nlimit","nstep","ninit","cb","inst","luaV_rawequalobj","luaP_opmodes","MASK1","MASK0","setarg","fullins","SETARG_Bx","POS_A","SIZE_C","ins","POS_OP","POS_C","MAXARG_Bx","BITRK","CREATE_ABC","CREATE_ABx","bc","CREATE_Ax","GET_OPCODE","GETARG_A","GETARG_B","GETARG_C","GETARG_Bx","GETARG_Ax","GETARG_sBx","MAXARG_A","MAXARG_Ax","MAXARG_B","MAXARG_C","MAXARG_sBx","MAXINDEXRK","NO_REG","OpArgK","OpArgN","OpArgR","OpArgU","OpCodes","POS_Ax","POS_B","POS_Bx","RKASK","SETARG_A","SETARG_Ax","SETARG_B","SETARG_C","SETARG_sBx","SET_OPCODE","SIZE_A","SIZE_Ax","SIZE_B","SIZE_Bx","SIZE_OP","getBMode","getCMode","getOpMode","iABC","iABx","iAsBx","iAx","testTMode","LUA_VERSUFFIX","luaopen_base","LUA_COLIBNAME","luaopen_coroutine","LUA_TABLIBNAME","luaopen_table","LUA_OSLIBNAME","luaopen_os","LUA_STRLIBNAME","luaopen_string","LUA_UTF8LIBNAME","luaopen_utf8","LUA_BITLIBNAME","LUA_MATHLIBNAME","luaopen_math","LUA_DBLIBNAME","luaopen_debug","LUA_LOADLIBNAME","luaopen_package","LUA_FENGARILIBNAME","luaopen_fengari","linit","luaL_openlibs","apply","construct","Reflect_deleteProperty","global_env","WorkerGlobalScope","self","eval","Reflect","deleteProperty","fApply","Function","target","thisArgument","argumentsList","args","push","isobject","js_tname","testjs","checkjs","pushjs","getmainthread","mainL","states","objects_seen","tojs","wrap","jscall","invoke","thisarg","n_results","gettable","prop","has","iter_next","iter","state","done","js_proxy","iterator","jsiterator","toPrimitive","hint","jslib","new","instanceof","typeof","getiter","get_iterator","Proxy","L_symbol","p_symbol","proxy_handlers","arg_length","desc","getOwnPropertyDescriptor","getPrototypeOf","ownKeys","setPrototypeOf","make_arrow_function","createproxy","raw_function","raw_arrow_function","valid_types","valid_types_as_luastring","fengariProxy","jsmt","__index","__newindex","__call","__pairs","first","for","index","keys","isArray","__len","FENGARI_INTEROP_VERSION","FENGARI_INTEROP_VERSION_MAJOR","FENGARI_INTEROP_VERSION_NUM","FENGARI_INTEROP_RELEASE","luaopen_js","luaU_dump","ZIO","fengari_argcheck","fengari_argcheckinteger","isvalid","index2addr","ttislcf","index2addr_","reverse","fromtv","pIdx","fromidx","toidx","fn","setclCvalue","auxsetstr","auxgetstr","narray","nrec","aux_upvalue","fi","seen","f_call","default_chunkname","checkresults","na","nr","getupvalref","fidx","panicf","errorf","index1","index2","o1","o2","writer","strip","warn","objindex","funcindex","up","ttisCclosure","G","ttislightuserdata","reader","chunkname","gt","luaS_newudata","lua_setallocf","u8","buffer","byteOffset","byteLength","jsstring","proxy","create_proxy","ttisthread","fidx1","fidx2","ref1","ref2","up2","luaZ_fill","EOZ","luaZ_buffer","luaZ_buffremove","luaZ_read","b_offset","luaZ_resetbuffer","luaZ_resizebuffer","lislalnum","lislalpha","RESERVED","TK_AND","TK_BREAK","FIRST_RESERVED","TK_DO","TK_ELSE","TK_ELSEIF","TK_END","TK_FALSE","TK_FOR","TK_FUNCTION","TK_GOTO","TK_IF","TK_IN","TK_LOCAL","TK_NIL","TK_NOT","TK_OR","TK_REPEAT","TK_RETURN","TK_THEN","TK_TRUE","TK_UNTIL","TK_WHILE","TK_IDIV","TK_CONCAT","TK_DOTS","TK_EQ","TK_GE","TK_LE","TK_NE","TK_SHL","TK_SHR","TK_DBCOLON","TK_EOS","TK_FLT","TK_INT","TK_NAME","TK_STRING","luaX_tokens","SemInfo","Token","token","seminfo","save","lexerror","luaX_token2str","currIsNewline","current","save_and_next","TVtrue","luaX_newstring","tpair","inclinenumber","linenumber","check_next1","check_next2","read_numeral","expo","txtToken","skip_sep","read_long_string","sep","skip","esccheck","gethexa","readhexaesc","utf8esc","readutf8desc","readdecesc","read_string","del","will","token_to_index","forEach","kidx","LexState","lastline","lookahead","fs","envn","isreserved","w","luaX_lookahead","luaX_next","luaX_setinput","firstchar","luaX_syntaxerror","luai_ctype_","BinOpr","OPR_ADD","OPR_AND","OPR_BAND","OPR_BOR","OPR_BXOR","OPR_CONCAT","OPR_DIV","OPR_EQ","OPR_GE","OPR_GT","OPR_IDIV","OPR_LE","OPR_LT","OPR_MOD","OPR_MUL","OPR_NE","OPR_NOBINOPR","OPR_OR","OPR_POW","OPR_SHL","OPR_SHR","OPR_SUB","UnOpr","OPR_BNOT","OPR_LEN","OPR_MINUS","OPR_NOT","OPR_NOUNOPR","NO_JUMP","getinstruction","luaK_checkstack","luaK_codeABC","luaK_codeABx","luaK_codeAsBx","luaK_codek","luaK_concat","luaK_dischargevars","luaK_exp2RK","luaK_exp2anyreg","luaK_exp2anyregup","luaK_exp2nextreg","luaK_exp2val","luaK_fixline","luaK_getlabel","luaK_goiffalse","luaK_goiftrue","luaK_indexed","luaK_infix","luaK_intK","luaK_jump","luaK_jumpto","luaK_nil","luaK_patchclose","luaK_patchlist","luaK_patchtohere","luaK_posfix","luaK_prefix","luaK_reserveregs","luaK_ret","luaK_self","luaK_setlist","luaK_setmultret","luaK_setoneret","luaK_setreturns","luaK_storevar","luaK_stringK","R","hasmultret","expkind","VCALL","VVARARG","eqstr","BlockCnt","firstlabel","firstgoto","nactvar","isloop","VVOID","VNIL","VTRUE","VFALSE","VK","VKFLT","VKINT","VNONRELOC","VLOCAL","VUPVAL","VINDEXED","VJMP","VRELOCABLE","expdesc","ival","nval","info","ind","vt","FuncState","bl","lasttarget","jpc","nk","np","firstlocal","nlocvars","freereg","Labellist","semerror","error_expected","checklimit","where","errorlimit","testnext","check","checknext","check_condition","check_match","who","str_checkname","init_exp","codestring","checkname","new_localvar","registerlocalvar","actvar","Vardesc","new_localvarliteral","getlocvar","adjustlocalvars","nvars","newupvalue","singlevaraux","vr","searchvar","markupval","searchupvalue","singlevar","adjust_assign","nexps","enterlevel","leavelevel","closegoto","label","gl","vname","findlabel","lb","newlabelentry","Labeldesc","findgotos","enterblock","open_func","leaveblock","breaklabel","tolevel","removevars","movegotosout","undefgoto","close_func","block_follow","withuntil","statlist","statement","fieldsel","yindex","expr","recfield","cc","nh","rkkey","closelistfield","tostore","listfield","field","constructor","ConsControl","lastlistfield","body","ismethod","new_fs","clp","addprototype","parlist","codeclosure","explist","funcargs","suffixedexp","primaryexp","priority","left","right","subexpr","uop","getunopr","simpleexp","getbinopr","nextop","block","LHS_assign","assignment","lh","vkisvar","nv","conflict","check_conflict","gotostat","labelstat","ll","checkrepeated","skipnoopstat","forbody","isnum","endfor","prep","forstat","fornum","indexname","forlist","test_then_block","escapelist","jf","funcstat","ifstat","whileinit","condexit","whilestat","repeat_init","bl1","bl2","repeatstat","localfunc","localstat","nret","retstat","exprstat","lexstate","funcstate","mainfunc","vkisinreg","lua_writestring","lua_writeline","TextDecoder","decoder","decode","stream","log","copy","opts","luaB_next","ipairsaux","luaB_error","finishpcall","load_aux","envidx","generic_reader","dofilecont","d1","d2","base_funcs","assert","collectgarbage","dofile","getmetatable","ipairs","load","env","loadfile","pairs","method","iszero","pairsmeta","pcall","print","rawequal","rawget","rawlen","rawset","select","setmetatable","parseInt","b_str2int","xpcall","getco","co","auxresume","luaB_auxwrap","luaB_cocreate","NL","co_funcs","isyieldable","running","yield","checkfield","checktab","aux_getn","addfield","set2","sort_comp","partition","lo","choosePivot","rnd","r4","tab_funcs","lsep","insert","TAB_R","move","pack","remove","sort","auxsort","random","unpack","MAX_SAFE_INTEGER","LUA_STRFTIMEOPTIONS","setfield","setallfields","time","utc","getUTCSeconds","getSeconds","getUTCMinutes","getMinutes","getUTCHours","getHours","getUTCDate","getDate","getUTCMonth","getMonth","getUTCFullYear","getFullYear","getUTCDay","getDay","Date","L_MAXDATEFIELD","getfield","delta","locale","days","shortDays","months","shortMonths","AM","PM","am","pm","formats","D","F","T","X","week_number","date","start_of_week","weekday","yday","push_pad_2","pad","checkoption","conv","option","oplen","l_checktime","syslib","stm","strftime","tzString","match","day","getTimezoneOffset","difftime","clock","performance","now","sprintf","L_ESC","strlen","posrelat","SIZELENMOD","lua_number2strx","is","Infinity","zero","fe","num2straux","FLAGS","isalpha","isdigit","iscntrl","isgraph","islower","isupper","isalnum","ispunct","isspace","isxdigit","addliteral","repeat","addquoted","point","ppoint","checkdp","scanformat","strfrmt","form","addlenmod","lenmod","lm","spec","Header","islittle","maxalign","digit","getnum","df","getnumlimit","getoption","opt","getdetails","totalsize","ntoalign","align","packint","unpackint","issigned","unpacknum","dv","setUint8","getFloat32","getFloat64","SPECIALS","MatchState","src_init","src_end","p_end","matchdepth","capture","classend","ms","match_class","matchbracketclass","ec","sig","singlematch","ep","matchbalance","cont","max_expand","min_expand","start_capture","end_capture","capture_to_close","match_capture","check_capture","ai","bi","array_cmp","gotodefault","gotoinit","push_onecapture","push_captures","nlevels","prepstate","lp","reprepstate","str_find_aux","find","nospecials","anchor","gmatch_aux","gm","lastmatch","add_value","tr","news","add_s","strlib","byte","posi","pose","char","dump","format","gmatch","GMatchState","gsub","srcl","max_s","lower","details","setFloat32","packsize","rep","totallen","pi","sub","start","end","ld","upper","createmetatable","iscont","u_posrelat","limits","utf8_decode","p_U","pushutfchar","iter_aux","dec","funcs","codepoint","codes","posj","offset","UTF8PATT","rand_state","l_rand","pushnumint","mathlib","acos","asin","atan","atan2","cos","deg","PI","exp","fmod","log2","log10","imax","imin","modf","ip","rad","low","randomseed","l_srand","sin","sqrt","tan","ult","getinput","checkstack","getthread","thread","settabss","settabsi","settabsb","treatstackoption","auxupvalue","checkupval","argf","argnup","HOOKKEY","hooknames","hookf","dblib","gethook","smask","unmakemask","getinfo","options","getlocal","nvar","getregistry","getupvalue","getuservalue","sethook","hooktable","makemask","setlocal","setupvalue","setuservalue","traceback","upvalueid","upvaluejoin","input","prompt","debug","lsys_load","fengari","JSLIBS","LUA_CSUBSEP","LUA_LSUBSEP","LUA_POF","LUA_OFSEP","AUXMARK","seeglb","readable","lookforfunc","sym","checkjslib","addtojslib","lsys_sym","setpath","fieldname","envname","dft","nver","noenv","plib","pushnexttemplate","searchpath","dirsep","findfile","pname","checkload","searcher_Lua","loadfunc","openfunc","mark","searcher_C","searcher_Croot","searcher_preload","findloader_cont","ll_require_cont","ll_require_cont2","pk_funcs","loadlib","ll_funcs","findloader","createjslibstable","searchers","createsearcherstable","__webpack_exports__","fengari__WEBPACK_IMPORTED_MODULE_0__","fengari_interop__WEBPACK_IMPORTED_MODULE_1__","interop","ok","SyntaxError","document","HTMLDocument","msghandler","ErrorEvent","bubbles","cancelable","lineno","run_lua_script","location","syntaxerror","configurable","currentScript","dispatchEvent","process_xhr_response","Event","contentTypeRegexp","luaVersionRegex","try_tag","tagName","contentTypeMatch","mimetype","hasAttribute","getAttribute","readyState","async","fetch","credentials","crossorigin","crossorigin_to_credentials","redirect","integrity","then","resp","arrayBuffer","catch","reason","onreadystatechange","innerHTML","run_lua_script_tag","MutationObserver","records","observer","record","addedNodes","observe","childList","subtree","querySelectorAll","hasjumps","tonumeral","make_tvalue","ek","pfrom","pl","getjump","fixjump","jmp","l1","l2","list","condjump","getjumpcontroloffset","getjumpcontrol","patchtestreg","node","removevalues","patchlistaux","vtarget","dtarget","luaK_code","dischargejpc","codeextraarg","newstack","freeexp","freeexps","e1","r1","r2","addk","luaK_numberK","boolK","code_loadbool","jump","discharge2reg","discharge2anyreg","need_value","exp2reg","final","p_t","fj","vk","nilK","negatecondition","jumponcond","ie","constfolding","validop","codebinexpval","rk2","rk1","opr","codecomp","codeunexpval","codenot","ereg","nelems","ex","LUAC_DATA","BytecodeParser","Z","intSize","size_tSize","instructionSize","integerSize","numberSize","arraybuffer","getInt32","LoadInteger","LoadByte","LoadSize_t","read","LoadInt","LoadNumber","LoadString","LoadFunction","psource","LoadCode","LoadConstants","LoadUpvalues","LoadProtos","LoadDebug","checkliteral","checksize","why","S","checkHeader","LUAC_VERSION","DumpState","write","DumpBlock","DumpByte","DumpInt","ab","setInt32","DumpInteger","DumpNumber","DumpString","DumpProtos","DumpFunction","DumpCode","DumpConstants","DumpUpvalues","DumpDebug","DumpHeader","__WEBPACK_AMD_DEFINE_RESULT__","re","not_string","not_bool","not_type","not_primitive","number","numeric_arg","json","not_json","text","modulo","placeholder","key_access","index_access","sign","parse_tree","argv","pad_character","pad_length","is_positive","cursor","tree_length","output","toExponential","toFixed","substring","slice","toLowerCase","valueOf","toUpperCase","replace","charAt","sprintf_format","sprintf_cache","_fmt","arg_names","field_list","replacement_field","field_match","sprintf_parse","vsprintf","loadedlibs"],"mappings":"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AAQ,GAAzBW,cAGJ,EACA,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,GAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,GAAO,GAAO,GAAO,GAAO,GAAO,GAAO,GAAO,GACjD,GAAO,GAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,GAAO,GAAO,GAAO,GAAO,GAAO,GAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,GAAO,GAAO,GAAO,GAAO,GAAO,GAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,EACjD,EAAO,EAAO,EAAO,EAAO,EAAO,EAAO,E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","file":"fengari-web.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"fengari\"] = factory();\n\telse\n\t\troot[\"fengari\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 34);\n","/**\n@license MIT\n\nCopyright © 2017-2018 Benoit Giannangeli\nCopyright © 2017-2018 Daurnimator\nCopyright © 1994–2017 Lua.org, PUC-Rio.\n*/\n\n\"use strict\";\n\nconst core = require(\"./fengaricore.js\");\n\nmodule.exports.FENGARI_AUTHORS = core.FENGARI_AUTHORS;\nmodule.exports.FENGARI_COPYRIGHT = core.FENGARI_COPYRIGHT;\nmodule.exports.FENGARI_RELEASE = core.FENGARI_RELEASE;\nmodule.exports.FENGARI_VERSION = core.FENGARI_VERSION;\nmodule.exports.FENGARI_VERSION_MAJOR = core.FENGARI_VERSION_MAJOR;\nmodule.exports.FENGARI_VERSION_MINOR = core.FENGARI_VERSION_MINOR;\nmodule.exports.FENGARI_VERSION_NUM = core.FENGARI_VERSION_NUM;\nmodule.exports.FENGARI_VERSION_RELEASE = core.FENGARI_VERSION_RELEASE;\n\nmodule.exports.luastring_eq = core.luastring_eq;\nmodule.exports.luastring_indexOf = core.luastring_indexOf;\nmodule.exports.luastring_of = core.luastring_of;\nmodule.exports.to_jsstring = core.to_jsstring;\nmodule.exports.to_luastring = core.to_luastring;\nmodule.exports.to_uristring = core.to_uristring;\n\nconst luaconf = require('./luaconf.js');\nconst lua = require('./lua.js');\nconst lauxlib = require('./lauxlib.js');\nconst lualib = require('./lualib.js');\n\nmodule.exports.luaconf = luaconf;\nmodule.exports.lua = lua;\nmodule.exports.lauxlib = lauxlib;\nmodule.exports.lualib = lualib;\n","\"use strict\";\n\n/*\n * Fengari specific string conversion functions\n */\n\nlet luastring_from;\nif (typeof Uint8Array.from === \"function\") {\n luastring_from = Uint8Array.from.bind(Uint8Array);\n} else {\n luastring_from = function(a) {\n let i = 0;\n let len = a.length;\n let r = new Uint8Array(len);\n while (len > i) r[i] = a[i++];\n return r;\n };\n}\n\nlet luastring_indexOf;\nif (typeof (new Uint8Array().indexOf) === \"function\") {\n luastring_indexOf = function(s, v, i) {\n return s.indexOf(v, i);\n };\n} else {\n /* Browsers that don't support Uint8Array.indexOf seem to allow using Array.indexOf on Uint8Array objects e.g. IE11 */\n let array_indexOf = [].indexOf;\n if (array_indexOf.call(new Uint8Array(1), 0) !== 0) throw Error(\"missing .indexOf\");\n luastring_indexOf = function(s, v, i) {\n return array_indexOf.call(s, v, i);\n };\n}\n\nlet luastring_of;\nif (typeof Uint8Array.of === \"function\") {\n luastring_of = Uint8Array.of.bind(Uint8Array);\n} else {\n luastring_of = function() {\n return luastring_from(arguments);\n };\n}\n\nconst is_luastring = function(s) {\n return s instanceof Uint8Array;\n};\n\n/* test two lua strings for equality */\nconst luastring_eq = function(a, b) {\n if (a !== b) {\n let len = a.length;\n if (len !== b.length) return false;\n /* XXX: Should this be a constant time algorithm? */\n for (let i=0; i 0xF4) {\n if (!replacement_char) throw RangeError(unicode_error_message);\n str += \"�\";\n } else if (u0 <= 0xDF) {\n /* two byte sequence */\n if (i >= to) {\n if (!replacement_char) throw RangeError(unicode_error_message);\n str += \"�\";\n continue;\n }\n let u1 = value[i++];\n if ((u1&0xC0) !== 0x80) {\n if (!replacement_char) throw RangeError(unicode_error_message);\n str += \"�\";\n continue;\n }\n str += String.fromCharCode(((u0 & 0x1F) << 6) + (u1 & 0x3F));\n } else if (u0 <= 0xEF) {\n /* three byte sequence */\n if (i+1 >= to) {\n if (!replacement_char) throw RangeError(unicode_error_message);\n str += \"�\";\n continue;\n }\n let u1 = value[i++];\n if ((u1&0xC0) !== 0x80) {\n if (!replacement_char) throw RangeError(unicode_error_message);\n str += \"�\";\n continue;\n }\n let u2 = value[i++];\n if ((u2&0xC0) !== 0x80) {\n if (!replacement_char) throw RangeError(unicode_error_message);\n str += \"�\";\n continue;\n }\n let u = ((u0 & 0x0F) << 12) + ((u1 & 0x3F) << 6) + (u2 & 0x3F);\n if (u <= 0xFFFF) { /* BMP codepoint */\n str += String.fromCharCode(u);\n } else { /* Astral codepoint */\n u -= 0x10000;\n let s1 = (u >> 10) + 0xD800;\n let s2 = (u % 0x400) + 0xDC00;\n str += String.fromCharCode(s1, s2);\n }\n } else {\n /* four byte sequence */\n if (i+2 >= to) {\n if (!replacement_char) throw RangeError(unicode_error_message);\n str += \"�\";\n continue;\n }\n let u1 = value[i++];\n if ((u1&0xC0) !== 0x80) {\n if (!replacement_char) throw RangeError(unicode_error_message);\n str += \"�\";\n continue;\n }\n let u2 = value[i++];\n if ((u2&0xC0) !== 0x80) {\n if (!replacement_char) throw RangeError(unicode_error_message);\n str += \"�\";\n continue;\n }\n let u3 = value[i++];\n if ((u3&0xC0) !== 0x80) {\n if (!replacement_char) throw RangeError(unicode_error_message);\n str += \"�\";\n continue;\n }\n /* Has to be astral codepoint */\n let u = ((u0 & 0x07) << 18) + ((u1 & 0x3F) << 12) + ((u2 & 0x3F) << 6) + (u3 & 0x3F);\n u -= 0x10000;\n let s1 = (u >> 10) + 0xD800;\n let s2 = (u % 0x400) + 0xDC00;\n str += String.fromCharCode(s1, s2);\n }\n }\n return str;\n};\n\n/* bytes allowed unescaped in a uri */\nconst uri_allowed = (\";,/?:@&=+$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,-_.!~*'()#\").split('').reduce(function(uri_allowed, c) {\n uri_allowed[c.charCodeAt(0)] = true;\n return uri_allowed;\n}, {});\n\n/* utility function to convert a lua string to a js string with uri escaping */\nconst to_uristring = function(a) {\n if (!is_luastring(a)) throw new TypeError(\"to_uristring expects a Uint8Array\");\n let s = \"\";\n for (let i=0; i> 6);\n outU8Array[outIdx++] = 0x80 | (u & 63);\n } else {\n /* This part is to work around possible lack of String.codePointAt */\n if (u >= 0xD800 && u <= 0xDBFF && (i+1) < len) {\n /* is first half of surrogate pair */\n let v = str.charCodeAt(i+1);\n if (v >= 0xDC00 && v <= 0xDFFF) {\n /* is valid low surrogate */\n i++;\n u = (u - 0xD800) * 0x400 + v + 0x2400;\n }\n }\n if (u <= 0xFFFF) {\n outU8Array[outIdx++] = 0xE0 | (u >> 12);\n outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63);\n outU8Array[outIdx++] = 0x80 | (u & 63);\n } else {\n outU8Array[outIdx++] = 0xF0 | (u >> 18);\n outU8Array[outIdx++] = 0x80 | ((u >> 12) & 63);\n outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63);\n outU8Array[outIdx++] = 0x80 | (u & 63);\n }\n }\n }\n outU8Array = luastring_from(outU8Array);\n\n if (cache) to_luastring_cache[str] = outU8Array;\n\n return outU8Array;\n};\n\nconst from_userstring = function(str) {\n if (!is_luastring(str)) {\n if (typeof str === \"string\") {\n str = to_luastring(str);\n } else {\n throw new TypeError(\"expects an array of bytes or javascript string\");\n }\n }\n return str;\n};\n\nmodule.exports.luastring_from = luastring_from;\nmodule.exports.luastring_indexOf = luastring_indexOf;\nmodule.exports.luastring_of = luastring_of;\nmodule.exports.is_luastring = is_luastring;\nmodule.exports.luastring_eq = luastring_eq;\nmodule.exports.to_jsstring = to_jsstring;\nmodule.exports.to_uristring = to_uristring;\nmodule.exports.to_luastring = to_luastring;\nmodule.exports.from_userstring = from_userstring;\n\n\n/* mark for precompiled code ('Lua') */\nconst LUA_SIGNATURE = to_luastring(\"\\x1bLua\");\n\nconst LUA_VERSION_MAJOR = \"5\";\nconst LUA_VERSION_MINOR = \"3\";\nconst LUA_VERSION_NUM = 503;\nconst LUA_VERSION_RELEASE = \"4\";\n\nconst LUA_VERSION = \"Lua \" + LUA_VERSION_MAJOR + \".\" + LUA_VERSION_MINOR;\nconst LUA_RELEASE = LUA_VERSION + \".\" + LUA_VERSION_RELEASE;\nconst LUA_COPYRIGHT = LUA_RELEASE + \" Copyright (C) 1994-2017 Lua.org, PUC-Rio\";\nconst LUA_AUTHORS = \"R. Ierusalimschy, L. H. de Figueiredo, W. Celes\";\n\nmodule.exports.LUA_SIGNATURE = LUA_SIGNATURE;\nmodule.exports.LUA_VERSION_MAJOR = LUA_VERSION_MAJOR;\nmodule.exports.LUA_VERSION_MINOR = LUA_VERSION_MINOR;\nmodule.exports.LUA_VERSION_NUM = LUA_VERSION_NUM;\nmodule.exports.LUA_VERSION_RELEASE = LUA_VERSION_RELEASE;\nmodule.exports.LUA_VERSION = LUA_VERSION;\nmodule.exports.LUA_RELEASE = LUA_RELEASE;\nmodule.exports.LUA_COPYRIGHT = LUA_COPYRIGHT;\nmodule.exports.LUA_AUTHORS = LUA_AUTHORS;\n\n\nconst thread_status = {\n LUA_OK: 0,\n LUA_YIELD: 1,\n LUA_ERRRUN: 2,\n LUA_ERRSYNTAX: 3,\n LUA_ERRMEM: 4,\n LUA_ERRGCMM: 5,\n LUA_ERRERR: 6\n};\n\nconst constant_types = {\n LUA_TNONE: -1,\n LUA_TNIL: 0,\n LUA_TBOOLEAN: 1,\n LUA_TLIGHTUSERDATA: 2,\n LUA_TNUMBER: 3,\n LUA_TSTRING: 4,\n LUA_TTABLE: 5,\n LUA_TFUNCTION: 6,\n LUA_TUSERDATA: 7,\n LUA_TTHREAD: 8,\n LUA_NUMTAGS: 9\n};\n\nconstant_types.LUA_TSHRSTR = constant_types.LUA_TSTRING | (0 << 4); /* short strings */\nconstant_types.LUA_TLNGSTR = constant_types.LUA_TSTRING | (1 << 4); /* long strings */\n\nconstant_types.LUA_TNUMFLT = constant_types.LUA_TNUMBER | (0 << 4); /* float numbers */\nconstant_types.LUA_TNUMINT = constant_types.LUA_TNUMBER | (1 << 4); /* integer numbers */\n\nconstant_types.LUA_TLCL = constant_types.LUA_TFUNCTION | (0 << 4); /* Lua closure */\nconstant_types.LUA_TLCF = constant_types.LUA_TFUNCTION | (1 << 4); /* light C function */\nconstant_types.LUA_TCCL = constant_types.LUA_TFUNCTION | (2 << 4); /* C closure */\n\n/*\n** Comparison and arithmetic functions\n*/\n\nconst LUA_OPADD = 0; /* ORDER TM, ORDER OP */\nconst LUA_OPSUB = 1;\nconst LUA_OPMUL = 2;\nconst LUA_OPMOD = 3;\nconst LUA_OPPOW = 4;\nconst LUA_OPDIV = 5;\nconst LUA_OPIDIV = 6;\nconst LUA_OPBAND = 7;\nconst LUA_OPBOR = 8;\nconst LUA_OPBXOR = 9;\nconst LUA_OPSHL = 10;\nconst LUA_OPSHR = 11;\nconst LUA_OPUNM = 12;\nconst LUA_OPBNOT = 13;\n\nconst LUA_OPEQ = 0;\nconst LUA_OPLT = 1;\nconst LUA_OPLE = 2;\n\nconst LUA_MINSTACK = 20;\n\nconst { LUAI_MAXSTACK } = require('./luaconf.js');\nconst LUA_REGISTRYINDEX = -LUAI_MAXSTACK - 1000;\n\nconst lua_upvalueindex = function(i) {\n return LUA_REGISTRYINDEX - i;\n};\n\n/* predefined values in the registry */\nconst LUA_RIDX_MAINTHREAD = 1;\nconst LUA_RIDX_GLOBALS = 2;\nconst LUA_RIDX_LAST = LUA_RIDX_GLOBALS;\n\nclass lua_Debug {\n constructor() {\n this.event = NaN;\n this.name = null; /* (n) */\n this.namewhat = null; /* (n) 'global', 'local', 'field', 'method' */\n this.what = null; /* (S) 'Lua', 'C', 'main', 'tail' */\n this.source = null; /* (S) */\n this.currentline = NaN; /* (l) */\n this.linedefined = NaN; /* (S) */\n this.lastlinedefined = NaN; /* (S) */\n this.nups = NaN; /* (u) number of upvalues */\n this.nparams = NaN; /* (u) number of parameters */\n this.isvararg = NaN; /* (u) */\n this.istailcall = NaN; /* (t) */\n this.short_src = null; /* (S) */\n /* private part */\n this.i_ci = null; /* active function */\n }\n}\n\n/*\n** Event codes\n*/\nconst LUA_HOOKCALL = 0;\nconst LUA_HOOKRET = 1;\nconst LUA_HOOKLINE = 2;\nconst LUA_HOOKCOUNT = 3;\nconst LUA_HOOKTAILCALL = 4;\n\n\n/*\n** Event masks\n*/\nconst LUA_MASKCALL = (1 << LUA_HOOKCALL);\nconst LUA_MASKRET = (1 << LUA_HOOKRET);\nconst LUA_MASKLINE = (1 << LUA_HOOKLINE);\nconst LUA_MASKCOUNT = (1 << LUA_HOOKCOUNT);\n\nmodule.exports.LUA_HOOKCALL = LUA_HOOKCALL;\nmodule.exports.LUA_HOOKCOUNT = LUA_HOOKCOUNT;\nmodule.exports.LUA_HOOKLINE = LUA_HOOKLINE;\nmodule.exports.LUA_HOOKRET = LUA_HOOKRET;\nmodule.exports.LUA_HOOKTAILCALL = LUA_HOOKTAILCALL;\nmodule.exports.LUA_MASKCALL = LUA_MASKCALL;\nmodule.exports.LUA_MASKCOUNT = LUA_MASKCOUNT;\nmodule.exports.LUA_MASKLINE = LUA_MASKLINE;\nmodule.exports.LUA_MASKRET = LUA_MASKRET;\nmodule.exports.LUA_MINSTACK = LUA_MINSTACK;\nmodule.exports.LUA_MULTRET = -1;\nmodule.exports.LUA_OPADD = LUA_OPADD;\nmodule.exports.LUA_OPBAND = LUA_OPBAND;\nmodule.exports.LUA_OPBNOT = LUA_OPBNOT;\nmodule.exports.LUA_OPBOR = LUA_OPBOR;\nmodule.exports.LUA_OPBXOR = LUA_OPBXOR;\nmodule.exports.LUA_OPDIV = LUA_OPDIV;\nmodule.exports.LUA_OPEQ = LUA_OPEQ;\nmodule.exports.LUA_OPIDIV = LUA_OPIDIV;\nmodule.exports.LUA_OPLE = LUA_OPLE;\nmodule.exports.LUA_OPLT = LUA_OPLT;\nmodule.exports.LUA_OPMOD = LUA_OPMOD;\nmodule.exports.LUA_OPMUL = LUA_OPMUL;\nmodule.exports.LUA_OPPOW = LUA_OPPOW;\nmodule.exports.LUA_OPSHL = LUA_OPSHL;\nmodule.exports.LUA_OPSHR = LUA_OPSHR;\nmodule.exports.LUA_OPSUB = LUA_OPSUB;\nmodule.exports.LUA_OPUNM = LUA_OPUNM;\nmodule.exports.LUA_REGISTRYINDEX = LUA_REGISTRYINDEX;\nmodule.exports.LUA_RIDX_GLOBALS = LUA_RIDX_GLOBALS;\nmodule.exports.LUA_RIDX_LAST = LUA_RIDX_LAST;\nmodule.exports.LUA_RIDX_MAINTHREAD = LUA_RIDX_MAINTHREAD;\nmodule.exports.constant_types = constant_types;\nmodule.exports.lua_Debug = lua_Debug;\nmodule.exports.lua_upvalueindex = lua_upvalueindex;\nmodule.exports.thread_status = thread_status;\n","\"use strict\";\n\nconst defs = require(\"./defs.js\");\nconst lapi = require(\"./lapi.js\");\nconst ldebug = require(\"./ldebug.js\");\nconst ldo = require(\"./ldo.js\");\nconst lstate = require(\"./lstate.js\");\n\nmodule.exports.LUA_AUTHORS = defs.LUA_AUTHORS;\nmodule.exports.LUA_COPYRIGHT = defs.LUA_COPYRIGHT;\nmodule.exports.LUA_ERRERR = defs.thread_status.LUA_ERRERR;\nmodule.exports.LUA_ERRGCMM = defs.thread_status.LUA_ERRGCMM;\nmodule.exports.LUA_ERRMEM = defs.thread_status.LUA_ERRMEM;\nmodule.exports.LUA_ERRRUN = defs.thread_status.LUA_ERRRUN;\nmodule.exports.LUA_ERRSYNTAX = defs.thread_status.LUA_ERRSYNTAX;\nmodule.exports.LUA_HOOKCALL = defs.LUA_HOOKCALL;\nmodule.exports.LUA_HOOKCOUNT = defs.LUA_HOOKCOUNT;\nmodule.exports.LUA_HOOKLINE = defs.LUA_HOOKLINE;\nmodule.exports.LUA_HOOKRET = defs.LUA_HOOKRET;\nmodule.exports.LUA_HOOKTAILCALL = defs.LUA_HOOKTAILCALL;\nmodule.exports.LUA_MASKCALL = defs.LUA_MASKCALL;\nmodule.exports.LUA_MASKCOUNT = defs.LUA_MASKCOUNT;\nmodule.exports.LUA_MASKLINE = defs.LUA_MASKLINE;\nmodule.exports.LUA_MASKRET = defs.LUA_MASKRET;\nmodule.exports.LUA_MINSTACK = defs.LUA_MINSTACK;\nmodule.exports.LUA_MULTRET = defs.LUA_MULTRET;\nmodule.exports.LUA_NUMTAGS = defs.constant_types.LUA_NUMTAGS;\nmodule.exports.LUA_OK = defs.thread_status.LUA_OK;\nmodule.exports.LUA_OPADD = defs.LUA_OPADD;\nmodule.exports.LUA_OPBAND = defs.LUA_OPBAND;\nmodule.exports.LUA_OPBNOT = defs.LUA_OPBNOT;\nmodule.exports.LUA_OPBOR = defs.LUA_OPBOR;\nmodule.exports.LUA_OPBXOR = defs.LUA_OPBXOR;\nmodule.exports.LUA_OPDIV = defs.LUA_OPDIV;\nmodule.exports.LUA_OPEQ = defs.LUA_OPEQ;\nmodule.exports.LUA_OPIDIV = defs.LUA_OPIDIV;\nmodule.exports.LUA_OPLE = defs.LUA_OPLE;\nmodule.exports.LUA_OPLT = defs.LUA_OPLT;\nmodule.exports.LUA_OPMOD = defs.LUA_OPMOD;\nmodule.exports.LUA_OPMUL = defs.LUA_OPMUL;\nmodule.exports.LUA_OPPOW = defs.LUA_OPPOW;\nmodule.exports.LUA_OPSHL = defs.LUA_OPSHL;\nmodule.exports.LUA_OPSHR = defs.LUA_OPSHR;\nmodule.exports.LUA_OPSUB = defs.LUA_OPSUB;\nmodule.exports.LUA_OPUNM = defs.LUA_OPUNM;\nmodule.exports.LUA_REGISTRYINDEX = defs.LUA_REGISTRYINDEX;\nmodule.exports.LUA_RELEASE = defs.LUA_RELEASE;\nmodule.exports.LUA_RIDX_GLOBALS = defs.LUA_RIDX_GLOBALS;\nmodule.exports.LUA_RIDX_LAST = defs.LUA_RIDX_LAST;\nmodule.exports.LUA_RIDX_MAINTHREAD = defs.LUA_RIDX_MAINTHREAD;\nmodule.exports.LUA_SIGNATURE = defs.LUA_SIGNATURE;\nmodule.exports.LUA_TNONE = defs.constant_types.LUA_TNONE;\nmodule.exports.LUA_TNIL = defs.constant_types.LUA_TNIL;\nmodule.exports.LUA_TBOOLEAN = defs.constant_types.LUA_TBOOLEAN;\nmodule.exports.LUA_TLIGHTUSERDATA = defs.constant_types.LUA_TLIGHTUSERDATA;\nmodule.exports.LUA_TNUMBER = defs.constant_types.LUA_TNUMBER;\nmodule.exports.LUA_TSTRING = defs.constant_types.LUA_TSTRING;\nmodule.exports.LUA_TTABLE = defs.constant_types.LUA_TTABLE;\nmodule.exports.LUA_TFUNCTION = defs.constant_types.LUA_TFUNCTION;\nmodule.exports.LUA_TUSERDATA = defs.constant_types.LUA_TUSERDATA;\nmodule.exports.LUA_TTHREAD = defs.constant_types.LUA_TTHREAD;\nmodule.exports.LUA_VERSION = defs.LUA_VERSION;\nmodule.exports.LUA_VERSION_MAJOR = defs.LUA_VERSION_MAJOR;\nmodule.exports.LUA_VERSION_MINOR = defs.LUA_VERSION_MINOR;\nmodule.exports.LUA_VERSION_NUM = defs.LUA_VERSION_NUM;\nmodule.exports.LUA_VERSION_RELEASE = defs.LUA_VERSION_RELEASE;\nmodule.exports.LUA_YIELD = defs.thread_status.LUA_YIELD;\nmodule.exports.lua_Debug = defs.lua_Debug;\nmodule.exports.lua_upvalueindex = defs.lua_upvalueindex;\nmodule.exports.lua_absindex = lapi.lua_absindex;\nmodule.exports.lua_arith = lapi.lua_arith;\nmodule.exports.lua_atpanic = lapi.lua_atpanic;\nmodule.exports.lua_atnativeerror = lapi.lua_atnativeerror;\nmodule.exports.lua_call = lapi.lua_call;\nmodule.exports.lua_callk = lapi.lua_callk;\nmodule.exports.lua_checkstack = lapi.lua_checkstack;\nmodule.exports.lua_close = lstate.lua_close;\nmodule.exports.lua_compare = lapi.lua_compare;\nmodule.exports.lua_concat = lapi.lua_concat;\nmodule.exports.lua_copy = lapi.lua_copy;\nmodule.exports.lua_createtable = lapi.lua_createtable;\nmodule.exports.lua_dump = lapi.lua_dump;\nmodule.exports.lua_error = lapi.lua_error;\nmodule.exports.lua_gc = lapi.lua_gc;\nmodule.exports.lua_getallocf = lapi.lua_getallocf;\nmodule.exports.lua_getextraspace = lapi.lua_getextraspace;\nmodule.exports.lua_getfield = lapi.lua_getfield;\nmodule.exports.lua_getglobal = lapi.lua_getglobal;\nmodule.exports.lua_gethook = ldebug.lua_gethook;\nmodule.exports.lua_gethookcount = ldebug.lua_gethookcount;\nmodule.exports.lua_gethookmask = ldebug.lua_gethookmask;\nmodule.exports.lua_geti = lapi.lua_geti;\nmodule.exports.lua_getinfo = ldebug.lua_getinfo;\nmodule.exports.lua_getlocal = ldebug.lua_getlocal;\nmodule.exports.lua_getmetatable = lapi.lua_getmetatable;\nmodule.exports.lua_getstack = ldebug.lua_getstack;\nmodule.exports.lua_gettable = lapi.lua_gettable;\nmodule.exports.lua_gettop = lapi.lua_gettop;\nmodule.exports.lua_getupvalue = lapi.lua_getupvalue;\nmodule.exports.lua_getuservalue = lapi.lua_getuservalue;\nmodule.exports.lua_insert = lapi.lua_insert;\nmodule.exports.lua_isboolean = lapi.lua_isboolean;\nmodule.exports.lua_iscfunction = lapi.lua_iscfunction;\nmodule.exports.lua_isfunction = lapi.lua_isfunction;\nmodule.exports.lua_isinteger = lapi.lua_isinteger;\nmodule.exports.lua_islightuserdata = lapi.lua_islightuserdata;\nmodule.exports.lua_isnil = lapi.lua_isnil;\nmodule.exports.lua_isnone = lapi.lua_isnone;\nmodule.exports.lua_isnoneornil = lapi.lua_isnoneornil;\nmodule.exports.lua_isnumber = lapi.lua_isnumber;\nmodule.exports.lua_isproxy = lapi.lua_isproxy;\nmodule.exports.lua_isstring = lapi.lua_isstring;\nmodule.exports.lua_istable = lapi.lua_istable;\nmodule.exports.lua_isthread = lapi.lua_isthread;\nmodule.exports.lua_isuserdata = lapi.lua_isuserdata;\nmodule.exports.lua_isyieldable = ldo.lua_isyieldable;\nmodule.exports.lua_len = lapi.lua_len;\nmodule.exports.lua_load = lapi.lua_load;\nmodule.exports.lua_newstate = lstate.lua_newstate;\nmodule.exports.lua_newtable = lapi.lua_newtable;\nmodule.exports.lua_newthread = lstate.lua_newthread;\nmodule.exports.lua_newuserdata = lapi.lua_newuserdata;\nmodule.exports.lua_next = lapi.lua_next;\nmodule.exports.lua_pcall = lapi.lua_pcall;\nmodule.exports.lua_pcallk = lapi.lua_pcallk;\nmodule.exports.lua_pop = lapi.lua_pop;\nmodule.exports.lua_pushboolean = lapi.lua_pushboolean;\nmodule.exports.lua_pushcclosure = lapi.lua_pushcclosure;\nmodule.exports.lua_pushcfunction = lapi.lua_pushcfunction;\nmodule.exports.lua_pushfstring = lapi.lua_pushfstring;\nmodule.exports.lua_pushglobaltable = lapi.lua_pushglobaltable;\nmodule.exports.lua_pushinteger = lapi.lua_pushinteger;\nmodule.exports.lua_pushjsclosure = lapi.lua_pushjsclosure;\nmodule.exports.lua_pushjsfunction = lapi.lua_pushjsfunction;\nmodule.exports.lua_pushlightuserdata = lapi.lua_pushlightuserdata;\nmodule.exports.lua_pushliteral = lapi.lua_pushliteral;\nmodule.exports.lua_pushlstring = lapi.lua_pushlstring;\nmodule.exports.lua_pushnil = lapi.lua_pushnil;\nmodule.exports.lua_pushnumber = lapi.lua_pushnumber;\nmodule.exports.lua_pushstring = lapi.lua_pushstring;\nmodule.exports.lua_pushthread = lapi.lua_pushthread;\nmodule.exports.lua_pushvalue = lapi.lua_pushvalue;\nmodule.exports.lua_pushvfstring = lapi.lua_pushvfstring;\nmodule.exports.lua_rawequal = lapi.lua_rawequal;\nmodule.exports.lua_rawget = lapi.lua_rawget;\nmodule.exports.lua_rawgeti = lapi.lua_rawgeti;\nmodule.exports.lua_rawgetp = lapi.lua_rawgetp;\nmodule.exports.lua_rawlen = lapi.lua_rawlen;\nmodule.exports.lua_rawset = lapi.lua_rawset;\nmodule.exports.lua_rawseti = lapi.lua_rawseti;\nmodule.exports.lua_rawsetp = lapi.lua_rawsetp;\nmodule.exports.lua_register = lapi.lua_register;\nmodule.exports.lua_remove = lapi.lua_remove;\nmodule.exports.lua_replace = lapi.lua_replace;\nmodule.exports.lua_resume = ldo.lua_resume;\nmodule.exports.lua_rotate = lapi.lua_rotate;\nmodule.exports.lua_setallof = ldo.lua_setallof;\nmodule.exports.lua_setfield = lapi.lua_setfield;\nmodule.exports.lua_setglobal = lapi.lua_setglobal;\nmodule.exports.lua_sethook = ldebug.lua_sethook;\nmodule.exports.lua_seti = lapi.lua_seti;\nmodule.exports.lua_setlocal = ldebug.lua_setlocal;\nmodule.exports.lua_setmetatable = lapi.lua_setmetatable;\nmodule.exports.lua_settable = lapi.lua_settable;\nmodule.exports.lua_settop = lapi.lua_settop;\nmodule.exports.lua_setupvalue = lapi.lua_setupvalue;\nmodule.exports.lua_setuservalue = lapi.lua_setuservalue;\nmodule.exports.lua_status = lapi.lua_status;\nmodule.exports.lua_stringtonumber = lapi.lua_stringtonumber;\nmodule.exports.lua_toboolean = lapi.lua_toboolean;\nmodule.exports.lua_todataview = lapi.lua_todataview;\nmodule.exports.lua_tointeger = lapi.lua_tointeger;\nmodule.exports.lua_tointegerx = lapi.lua_tointegerx;\nmodule.exports.lua_tojsstring = lapi.lua_tojsstring;\nmodule.exports.lua_tolstring = lapi.lua_tolstring;\nmodule.exports.lua_tonumber = lapi.lua_tonumber;\nmodule.exports.lua_tonumberx = lapi.lua_tonumberx;\nmodule.exports.lua_topointer = lapi.lua_topointer;\nmodule.exports.lua_toproxy = lapi.lua_toproxy;\nmodule.exports.lua_tostring = lapi.lua_tostring;\nmodule.exports.lua_tothread = lapi.lua_tothread;\nmodule.exports.lua_touserdata = lapi.lua_touserdata;\nmodule.exports.lua_type = lapi.lua_type;\nmodule.exports.lua_typename = lapi.lua_typename;\nmodule.exports.lua_upvalueid = lapi.lua_upvalueid;\nmodule.exports.lua_upvaluejoin = lapi.lua_upvaluejoin;\nmodule.exports.lua_version = lapi.lua_version;\nmodule.exports.lua_xmove = lapi.lua_xmove;\nmodule.exports.lua_yield = ldo.lua_yield;\nmodule.exports.lua_yieldk = ldo.lua_yieldk;\nmodule.exports.lua_tocfunction = lapi.lua_tocfunction;\n","\"use strict\";\n\nconst conf = (process.env.FENGARICONF ? JSON.parse(process.env.FENGARICONF) : {});\n\nconst {\n LUA_VERSION_MAJOR,\n LUA_VERSION_MINOR,\n to_luastring\n} = require('./defs.js');\n\n/*\n** LUA_PATH_SEP is the character that separates templates in a path.\n** LUA_PATH_MARK is the string that marks the substitution points in a\n** template.\n** LUA_EXEC_DIR in a Windows path is replaced by the executable's\n** directory.\n*/\nconst LUA_PATH_SEP = \";\";\nmodule.exports.LUA_PATH_SEP = LUA_PATH_SEP;\n\nconst LUA_PATH_MARK = \"?\";\nmodule.exports.LUA_PATH_MARK = LUA_PATH_MARK;\n\nconst LUA_EXEC_DIR = \"!\";\nmodule.exports.LUA_EXEC_DIR = LUA_EXEC_DIR;\n\n/*\n@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for\n** Lua libraries.\n@@ LUA_JSPATH_DEFAULT is the default path that Lua uses to look for\n** JS libraries.\n** CHANGE them if your machine has a non-conventional directory\n** hierarchy or if you want to install your libraries in\n** non-conventional directories.\n*/\nconst LUA_VDIR = LUA_VERSION_MAJOR + \".\" + LUA_VERSION_MINOR;\nmodule.exports.LUA_VDIR = LUA_VDIR;\n\nif (typeof process === \"undefined\") {\n const LUA_DIRSEP = \"/\";\n module.exports.LUA_DIRSEP = LUA_DIRSEP;\n\n const LUA_LDIR = \"./lua/\" + LUA_VDIR + \"/\";\n module.exports.LUA_LDIR = LUA_LDIR;\n\n const LUA_JSDIR = LUA_LDIR;\n module.exports.LUA_JSDIR = LUA_JSDIR;\n\n const LUA_PATH_DEFAULT = to_luastring(\n LUA_LDIR + \"?.lua;\" + LUA_LDIR + \"?/init.lua;\" +\n /* LUA_JSDIR excluded as it is equal to LUA_LDIR */\n \"./?.lua;./?/init.lua\"\n );\n module.exports.LUA_PATH_DEFAULT = LUA_PATH_DEFAULT;\n\n const LUA_JSPATH_DEFAULT = to_luastring(\n LUA_JSDIR + \"?.js;\" + LUA_JSDIR + \"loadall.js;./?.js\"\n );\n module.exports.LUA_JSPATH_DEFAULT = LUA_JSPATH_DEFAULT;\n} else if (require('os').platform() === 'win32') {\n const LUA_DIRSEP = \"\\\\\";\n module.exports.LUA_DIRSEP = LUA_DIRSEP;\n\n /*\n ** In Windows, any exclamation mark ('!') in the path is replaced by the\n ** path of the directory of the executable file of the current process.\n */\n const LUA_LDIR = \"!\\\\lua\\\\\";\n module.exports.LUA_LDIR = LUA_LDIR;\n\n const LUA_JSDIR = \"!\\\\\";\n module.exports.LUA_JSDIR = LUA_JSDIR;\n\n const LUA_SHRDIR = \"!\\\\..\\\\share\\\\lua\\\\\" + LUA_VDIR + \"\\\\\";\n module.exports.LUA_SHRDIR = LUA_SHRDIR;\n\n const LUA_PATH_DEFAULT = to_luastring(\n LUA_LDIR + \"?.lua;\" + LUA_LDIR + \"?\\\\init.lua;\" +\n LUA_JSDIR + \"?.lua;\" + LUA_JSDIR + \"?\\\\init.lua;\" +\n LUA_SHRDIR + \"?.lua;\" + LUA_SHRDIR + \"?\\\\init.lua;\" +\n \".\\\\?.lua;.\\\\?\\\\init.lua\"\n );\n module.exports.LUA_PATH_DEFAULT = LUA_PATH_DEFAULT;\n\n const LUA_JSPATH_DEFAULT = to_luastring(\n LUA_JSDIR + \"?.js;\" +\n LUA_JSDIR + \"..\\\\share\\\\lua\\\\\" + LUA_VDIR + \"\\\\?.js;\" +\n LUA_JSDIR + \"loadall.js;.\\\\?.js\"\n );\n module.exports.LUA_JSPATH_DEFAULT = LUA_JSPATH_DEFAULT;\n} else {\n const LUA_DIRSEP = \"/\";\n module.exports.LUA_DIRSEP = LUA_DIRSEP;\n\n const LUA_ROOT = \"/usr/local/\";\n module.exports.LUA_ROOT = LUA_ROOT;\n const LUA_ROOT2 = \"/usr/\";\n\n const LUA_LDIR = LUA_ROOT + \"share/lua/\" + LUA_VDIR + \"/\";\n const LUA_LDIR2 = LUA_ROOT2 + \"share/lua/\" + LUA_VDIR + \"/\";\n module.exports.LUA_LDIR = LUA_LDIR;\n\n const LUA_JSDIR = LUA_LDIR;\n module.exports.LUA_JSDIR = LUA_JSDIR;\n const LUA_JSDIR2 = LUA_LDIR2;\n\n const LUA_PATH_DEFAULT = to_luastring(\n LUA_LDIR + \"?.lua;\" + LUA_LDIR + \"?/init.lua;\" +\n LUA_LDIR2 + \"?.lua;\" + LUA_LDIR2 + \"?/init.lua;\" +\n /* LUA_JSDIR(2) excluded as it is equal to LUA_LDIR(2) */\n \"./?.lua;./?/init.lua\"\n );\n module.exports.LUA_PATH_DEFAULT = LUA_PATH_DEFAULT;\n\n const LUA_JSPATH_DEFAULT = to_luastring(\n LUA_JSDIR + \"?.js;\" + LUA_JSDIR + \"loadall.js;\" +\n LUA_JSDIR2 + \"?.js;\" + LUA_JSDIR2 + \"loadall.js;\" +\n \"./?.js\"\n );\n module.exports.LUA_JSPATH_DEFAULT = LUA_JSPATH_DEFAULT;\n}\n\n/*\n@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a\n@@ a float mark ('.0').\n** This macro is not on by default even in compatibility mode,\n** because this is not really an incompatibility.\n*/\nconst LUA_COMPAT_FLOATSTRING = conf.LUA_COMPAT_FLOATSTRING || false;\n\nconst LUA_MAXINTEGER = 2147483647;\nconst LUA_MININTEGER = -2147483648;\n\n/*\n@@ LUAI_MAXSTACK limits the size of the Lua stack.\n** CHANGE it if you need a different limit. This limit is arbitrary;\n** its only purpose is to stop Lua from consuming unlimited stack\n** space (and to reserve some numbers for pseudo-indices).\n*/\nconst LUAI_MAXSTACK = conf.LUAI_MAXSTACK || 1000000;\n\n/*\n@@ LUA_IDSIZE gives the maximum size for the description of the source\n@@ of a function in debug information.\n** CHANGE it if you want a different size.\n*/\nconst LUA_IDSIZE = conf.LUA_IDSIZE || (60-1); /* fengari uses 1 less than lua as we don't embed the null byte */\n\nconst lua_integer2str = function(n) {\n return String(n); /* should match behaviour of LUA_INTEGER_FMT */\n};\n\nconst lua_number2str = function(n) {\n return String(Number(n.toPrecision(14))); /* should match behaviour of LUA_NUMBER_FMT */\n};\n\nconst lua_numbertointeger = function(n) {\n return n >= LUA_MININTEGER && n < -LUA_MININTEGER ? n : false;\n};\n\nconst LUA_INTEGER_FRMLEN = \"\";\nconst LUA_NUMBER_FRMLEN = \"\";\n\nconst LUA_INTEGER_FMT = `%${LUA_INTEGER_FRMLEN}d`;\nconst LUA_NUMBER_FMT = \"%.14g\";\n\nconst lua_getlocaledecpoint = function() {\n /* we hard-code the decimal point to '.' as a user cannot change the\n locale in most JS environments, and in that you can, a multi-byte\n locale is common.\n */\n return 46 /* '.'.charCodeAt(0) */;\n};\n\nconst luai_apicheck = function(l, e) {\n if (!e) throw Error(e);\n};\n\n/*\n@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.\n*/\nconst LUAL_BUFFERSIZE = conf.LUAL_BUFFERSIZE || 8192;\n\n// See: http://croquetweak.blogspot.fr/2014/08/deconstructing-floats-frexp-and-ldexp.html\nconst frexp = function(value) {\n if (value === 0) return [value, 0];\n var data = new DataView(new ArrayBuffer(8));\n data.setFloat64(0, value);\n var bits = (data.getUint32(0) >>> 20) & 0x7FF;\n if (bits === 0) { // denormal\n data.setFloat64(0, value * Math.pow(2, 64)); // exp + 64\n bits = ((data.getUint32(0) >>> 20) & 0x7FF) - 64;\n }\n var exponent = bits - 1022;\n var mantissa = ldexp(value, -exponent);\n return [mantissa, exponent];\n};\n\nconst ldexp = function(mantissa, exponent) {\n var steps = Math.min(3, Math.ceil(Math.abs(exponent) / 1023));\n var result = mantissa;\n for (var i = 0; i < steps; i++)\n result *= Math.pow(2, Math.floor((exponent + i) / steps));\n return result;\n};\n\nmodule.exports.LUAI_MAXSTACK = LUAI_MAXSTACK;\nmodule.exports.LUA_COMPAT_FLOATSTRING = LUA_COMPAT_FLOATSTRING;\nmodule.exports.LUA_IDSIZE = LUA_IDSIZE;\nmodule.exports.LUA_INTEGER_FMT = LUA_INTEGER_FMT;\nmodule.exports.LUA_INTEGER_FRMLEN = LUA_INTEGER_FRMLEN;\nmodule.exports.LUA_MAXINTEGER = LUA_MAXINTEGER;\nmodule.exports.LUA_MININTEGER = LUA_MININTEGER;\nmodule.exports.LUA_NUMBER_FMT = LUA_NUMBER_FMT;\nmodule.exports.LUA_NUMBER_FRMLEN = LUA_NUMBER_FRMLEN;\nmodule.exports.LUAL_BUFFERSIZE = LUAL_BUFFERSIZE;\nmodule.exports.frexp = frexp;\nmodule.exports.ldexp = ldexp;\nmodule.exports.lua_getlocaledecpoint = lua_getlocaledecpoint;\nmodule.exports.lua_integer2str = lua_integer2str;\nmodule.exports.lua_number2str = lua_number2str;\nmodule.exports.lua_numbertointeger = lua_numbertointeger;\nmodule.exports.luai_apicheck = luai_apicheck;\n","\"use strict\";\n\nconst { luai_apicheck } = require(\"./luaconf.js\");\n\nconst lua_assert = function(c) {\n if (!c) throw Error(\"assertion failed\");\n};\nmodule.exports.lua_assert = lua_assert;\n\nmodule.exports.luai_apicheck = luai_apicheck || function(l, e) { return lua_assert(e); };\n\nconst api_check = function(l, e, msg) {\n return luai_apicheck(l, e && msg);\n};\nmodule.exports.api_check = api_check;\n\nconst LUAI_MAXCCALLS = 200;\nmodule.exports.LUAI_MAXCCALLS = LUAI_MAXCCALLS;\n\n/* minimum size for string buffer */\nconst LUA_MINBUFFER = 32;\nmodule.exports.LUA_MINBUFFER = LUA_MINBUFFER;\n\nconst luai_nummod = function(L, a, b) {\n let m = a % b;\n if ((m*b) < 0)\n m += b;\n return m;\n};\nmodule.exports.luai_nummod = luai_nummod;\n\n// If later integers are more than 32bit, LUA_MAXINTEGER will then be != MAX_INT\nconst MAX_INT = 2147483647;\nmodule.exports.MAX_INT = MAX_INT;\nconst MIN_INT = -2147483648;\nmodule.exports.MIN_INT = MIN_INT;\n","/* Fengari specific functions\n *\n * This file includes fengari-specific data or and functionality for users to\n * manipulate fengari's string type.\n * The fields are exposed to the user on the 'fengari' entry point; however to\n * avoid a dependency on defs.js from lauxlib.js they are defined in this file.\n */\n\nconst defs = require(\"./defs.js\");\n\nconst FENGARI_VERSION_MAJOR = \"0\";\nconst FENGARI_VERSION_MINOR = \"1\";\nconst FENGARI_VERSION_NUM = 1;\nconst FENGARI_VERSION_RELEASE = \"4\";\nconst FENGARI_VERSION = \"Fengari \" + FENGARI_VERSION_MAJOR + \".\" + FENGARI_VERSION_MINOR;\nconst FENGARI_RELEASE = FENGARI_VERSION + \".\" + FENGARI_VERSION_RELEASE;\nconst FENGARI_AUTHORS = \"B. Giannangeli, Daurnimator\";\nconst FENGARI_COPYRIGHT = FENGARI_RELEASE + \" Copyright (C) 2017-2018 \" + FENGARI_AUTHORS + \"\\nBased on: \" + defs.LUA_COPYRIGHT;\n\nmodule.exports.FENGARI_AUTHORS = FENGARI_AUTHORS;\nmodule.exports.FENGARI_COPYRIGHT = FENGARI_COPYRIGHT;\nmodule.exports.FENGARI_RELEASE = FENGARI_RELEASE;\nmodule.exports.FENGARI_VERSION = FENGARI_VERSION;\nmodule.exports.FENGARI_VERSION_MAJOR = FENGARI_VERSION_MAJOR;\nmodule.exports.FENGARI_VERSION_MINOR = FENGARI_VERSION_MINOR;\nmodule.exports.FENGARI_VERSION_NUM = FENGARI_VERSION_NUM;\nmodule.exports.FENGARI_VERSION_RELEASE = FENGARI_VERSION_RELEASE;\nmodule.exports.is_luastring = defs.is_luastring;\nmodule.exports.luastring_eq = defs.luastring_eq;\nmodule.exports.luastring_from = defs.luastring_from;\nmodule.exports.luastring_indexOf = defs.luastring_indexOf;\nmodule.exports.luastring_of = defs.luastring_of;\nmodule.exports.to_jsstring = defs.to_jsstring;\nmodule.exports.to_luastring = defs.to_luastring;\nmodule.exports.to_uristring = defs.to_uristring;\nmodule.exports.from_userstring = defs.from_userstring;\n","\"use strict\";\n\nconst {\n LUA_OPADD,\n LUA_OPBAND,\n LUA_OPBNOT,\n LUA_OPBOR,\n LUA_OPBXOR,\n LUA_OPDIV,\n LUA_OPIDIV,\n LUA_OPMOD,\n LUA_OPMUL,\n LUA_OPPOW,\n LUA_OPSHL,\n LUA_OPSHR,\n LUA_OPSUB,\n LUA_OPUNM,\n constant_types: {\n LUA_NUMTAGS,\n LUA_TBOOLEAN,\n LUA_TCCL,\n LUA_TFUNCTION,\n LUA_TLCF,\n LUA_TLCL,\n LUA_TLIGHTUSERDATA,\n LUA_TLNGSTR,\n LUA_TNIL,\n LUA_TNUMBER,\n LUA_TNUMFLT,\n LUA_TNUMINT,\n LUA_TSHRSTR,\n LUA_TSTRING,\n LUA_TTABLE,\n LUA_TTHREAD,\n LUA_TUSERDATA\n },\n from_userstring,\n luastring_indexOf,\n luastring_of,\n to_jsstring,\n to_luastring\n} = require('./defs.js');\nconst {\n lisdigit,\n lisprint,\n lisspace,\n lisxdigit\n} = require('./ljstype.js');\nconst ldebug = require('./ldebug.js');\nconst ldo = require('./ldo.js');\nconst lstate = require('./lstate.js');\nconst {\n luaS_bless,\n luaS_new\n} = require('./lstring.js');\nconst ltable = require('./ltable.js');\nconst {\n LUA_COMPAT_FLOATSTRING,\n ldexp,\n lua_integer2str,\n lua_number2str\n} = require('./luaconf.js');\nconst lvm = require('./lvm.js');\nconst {\n MAX_INT,\n luai_nummod,\n lua_assert\n} = require(\"./llimits.js\");\nconst ltm = require('./ltm.js');\n\nconst LUA_TPROTO = LUA_NUMTAGS;\nconst LUA_TDEADKEY = LUA_NUMTAGS+1;\n\nclass TValue {\n\n constructor(type, value) {\n this.type = type;\n this.value = value;\n }\n\n /* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */\n ttype() {\n return this.type & 0x3F;\n }\n\n /* type tag of a TValue with no variants (bits 0-3) */\n ttnov() {\n return this.type & 0x0F;\n }\n\n checktag(t) {\n return this.type === t;\n }\n\n checktype(t) {\n return this.ttnov() === t;\n }\n\n ttisnumber() {\n return this.checktype(LUA_TNUMBER);\n }\n\n ttisfloat() {\n return this.checktag(LUA_TNUMFLT);\n }\n\n ttisinteger() {\n return this.checktag(LUA_TNUMINT);\n }\n\n ttisnil() {\n return this.checktag(LUA_TNIL);\n }\n\n ttisboolean() {\n return this.checktag(LUA_TBOOLEAN);\n }\n\n ttislightuserdata() {\n return this.checktag(LUA_TLIGHTUSERDATA);\n }\n\n ttisstring() {\n return this.checktype(LUA_TSTRING);\n }\n\n ttisshrstring() {\n return this.checktag(LUA_TSHRSTR);\n }\n\n ttislngstring() {\n return this.checktag(LUA_TLNGSTR);\n }\n\n ttistable() {\n return this.checktag(LUA_TTABLE);\n }\n\n ttisfunction() {\n return this.checktype(LUA_TFUNCTION);\n }\n\n ttisclosure() {\n return (this.type & 0x1F) === LUA_TFUNCTION;\n }\n\n ttisCclosure() {\n return this.checktag(LUA_TCCL);\n }\n\n ttisLclosure() {\n return this.checktag(LUA_TLCL);\n }\n\n ttislcf() {\n return this.checktag(LUA_TLCF);\n }\n\n ttisfulluserdata() {\n return this.checktag(LUA_TUSERDATA);\n }\n\n ttisthread() {\n return this.checktag(LUA_TTHREAD);\n }\n\n ttisdeadkey() {\n return this.checktag(LUA_TDEADKEY);\n }\n\n l_isfalse() {\n return this.ttisnil() || (this.ttisboolean() && this.value === false);\n }\n\n setfltvalue(x) {\n this.type = LUA_TNUMFLT;\n this.value = x;\n }\n\n chgfltvalue(x) {\n lua_assert(this.type == LUA_TNUMFLT);\n this.value = x;\n }\n\n setivalue(x) {\n this.type = LUA_TNUMINT;\n this.value = x;\n }\n\n chgivalue(x) {\n lua_assert(this.type == LUA_TNUMINT);\n this.value = x;\n }\n\n setnilvalue() {\n this.type = LUA_TNIL;\n this.value = null;\n }\n\n setfvalue(x) {\n this.type = LUA_TLCF;\n this.value = x;\n }\n\n setpvalue(x) {\n this.type = LUA_TLIGHTUSERDATA;\n this.value = x;\n }\n\n setbvalue(x) {\n this.type = LUA_TBOOLEAN;\n this.value = x;\n }\n\n setsvalue(x) {\n this.type = LUA_TLNGSTR; /* LUA_TSHRSTR? */\n this.value = x;\n }\n\n setuvalue(x) {\n this.type = LUA_TUSERDATA;\n this.value = x;\n }\n\n setthvalue(x) {\n this.type = LUA_TTHREAD;\n this.value = x;\n }\n\n setclLvalue(x) {\n this.type = LUA_TLCL;\n this.value = x;\n }\n\n setclCvalue(x) {\n this.type = LUA_TCCL;\n this.value = x;\n }\n\n sethvalue(x) {\n this.type = LUA_TTABLE;\n this.value = x;\n }\n\n setdeadvalue() {\n this.type = LUA_TDEADKEY;\n this.value = null;\n }\n\n setfrom(tv) { /* in lua C source setobj2t is often used for this */\n this.type = tv.type;\n this.value = tv.value;\n }\n\n tsvalue() {\n lua_assert(this.ttisstring());\n return this.value;\n }\n\n svalue() {\n return this.tsvalue().getstr();\n }\n\n vslen() {\n return this.tsvalue().tsslen();\n }\n\n jsstring(from, to) {\n return to_jsstring(this.svalue(), from, to, true);\n }\n}\n\nconst pushobj2s = function(L, tv) {\n L.stack[L.top++] = new TValue(tv.type, tv.value);\n};\nconst pushsvalue2s = function(L, ts) {\n L.stack[L.top++] = new TValue(LUA_TLNGSTR, ts);\n};\n/* from stack to (same) stack */\nconst setobjs2s = function(L, newidx, oldidx) {\n L.stack[newidx].setfrom(L.stack[oldidx]);\n};\n/* to stack (not from same stack) */\nconst setobj2s = function(L, newidx, oldtv) {\n L.stack[newidx].setfrom(oldtv);\n};\nconst setsvalue2s = function(L, newidx, ts) {\n L.stack[newidx].setsvalue(ts);\n};\n\nconst luaO_nilobject = new TValue(LUA_TNIL, null);\nObject.freeze(luaO_nilobject);\nmodule.exports.luaO_nilobject = luaO_nilobject;\n\nclass LClosure {\n\n constructor(L, n) {\n this.id = L.l_G.id_counter++;\n\n this.p = null;\n this.nupvalues = n;\n this.upvals = new Array(n); /* list of upvalues. initialised in luaF_initupvals */\n }\n\n}\n\nclass CClosure {\n\n constructor(L, f, n) {\n this.id = L.l_G.id_counter++;\n\n this.f = f;\n this.nupvalues = n;\n this.upvalue = new Array(n); /* list of upvalues as TValues */\n while (n--) {\n this.upvalue[n] = new TValue(LUA_TNIL, null);\n }\n }\n\n}\n\nclass Udata {\n\n constructor(L, size) {\n this.id = L.l_G.id_counter++;\n\n this.metatable = null;\n this.uservalue = new TValue(LUA_TNIL, null);\n this.len = size;\n this.data = Object.create(null); // ignores size argument\n }\n\n}\n\n/*\n** Description of a local variable for function prototypes\n** (used for debug information)\n*/\nclass LocVar {\n constructor() {\n this.varname = null;\n this.startpc = NaN; /* first point where variable is active */\n this.endpc = NaN; /* first point where variable is dead */\n }\n}\n\nconst RETS = to_luastring(\"...\");\nconst PRE = to_luastring(\"[string \\\"\");\nconst POS = to_luastring(\"\\\"]\");\n\nconst luaO_chunkid = function(source, bufflen) {\n let l = source.length;\n let out;\n if (source[0] === 61 /* ('=').charCodeAt(0) */) { /* 'literal' source */\n if (l < bufflen) { /* small enough? */\n out = new Uint8Array(l-1);\n out.set(source.subarray(1));\n } else { /* truncate it */\n out = new Uint8Array(bufflen);\n out.set(source.subarray(1, bufflen+1));\n }\n } else if (source[0] === 64 /* ('@').charCodeAt(0) */) { /* file name */\n if (l <= bufflen) { /* small enough? */\n out = new Uint8Array(l-1);\n out.set(source.subarray(1));\n } else { /* add '...' before rest of name */\n out = new Uint8Array(bufflen);\n out.set(RETS);\n bufflen -= RETS.length;\n out.set(source.subarray(l - bufflen), RETS.length);\n }\n } else { /* string; format as [string \"source\"] */\n out = new Uint8Array(bufflen);\n let nli = luastring_indexOf(source, 10 /* ('\\n').charCodeAt(0) */); /* find first new line (if any) */\n out.set(PRE); /* add prefix */\n let out_i = PRE.length;\n bufflen -= PRE.length + RETS.length + POS.length; /* save space for prefix+suffix */\n if (l < bufflen && nli === -1) { /* small one-line source? */\n out.set(source, out_i); /* keep it */\n out_i += source.length;\n } else {\n if (nli !== -1) l = nli; /* stop at first newline */\n if (l > bufflen) l = bufflen;\n out.set(source.subarray(0, l), out_i);\n out_i += l;\n out.set(RETS, out_i);\n out_i += RETS.length;\n }\n out.set(POS, out_i);\n out_i += POS.length;\n out = out.subarray(0, out_i);\n }\n return out;\n};\n\nconst luaO_hexavalue = function(c) {\n if (lisdigit(c)) return c - 48;\n else return (c & 0xdf) - 55;\n};\n\nconst UTF8BUFFSZ = 8;\n\nconst luaO_utf8esc = function(buff, x) {\n let n = 1; /* number of bytes put in buffer (backwards) */\n lua_assert(x <= 0x10FFFF);\n if (x < 0x80) /* ascii? */\n buff[UTF8BUFFSZ - 1] = x;\n else { /* need continuation bytes */\n let mfb = 0x3f; /* maximum that fits in first byte */\n do {\n buff[UTF8BUFFSZ - (n++)] = 0x80 | (x & 0x3f);\n x >>= 6; /* remove added bits */\n mfb >>= 1; /* now there is one less bit available in first byte */\n } while (x > mfb); /* still needs continuation byte? */\n buff[UTF8BUFFSZ - n] = (~mfb << 1) | x; /* add first byte */\n }\n return n;\n};\n\n/* maximum number of significant digits to read (to avoid overflows\n even with single floats) */\nconst MAXSIGDIG = 30;\n\n/*\n** convert an hexadecimal numeric string to a number, following\n** C99 specification for 'strtod'\n*/\nconst lua_strx2number = function(s) {\n let i = 0;\n let r = 0.0; /* result (accumulator) */\n let sigdig = 0; /* number of significant digits */\n let nosigdig = 0; /* number of non-significant digits */\n let e = 0; /* exponent correction */\n let neg; /* 1 if number is negative */\n let hasdot = false; /* true after seen a dot */\n while (lisspace(s[i])) i++; /* skip initial spaces */\n if ((neg = (s[i] === 45 /* ('-').charCodeAt(0) */))) i++; /* check signal */\n else if (s[i] === 43 /* ('+').charCodeAt(0) */) i++;\n if (!(s[i] === 48 /* ('0').charCodeAt(0) */ && (s[i+1] === 120 /* ('x').charCodeAt(0) */ || s[i+1] === 88 /* ('X').charCodeAt(0) */))) /* check '0x' */\n return null; /* invalid format (no '0x') */\n for (i += 2; ; i++) { /* skip '0x' and read numeral */\n if (s[i] === 46 /* ('.').charCodeAt(0) i.e. dot/lua_getlocaledecpoint(); */) {\n if (hasdot) break; /* second dot? stop loop */\n else hasdot = true;\n } else if (lisxdigit(s[i])) {\n if (sigdig === 0 && s[i] === 48 /* ('0').charCodeAt(0) */) /* non-significant digit (zero)? */\n nosigdig++;\n else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */\n r = (r * 16) + luaO_hexavalue(s[i]);\n else e++; /* too many digits; ignore, but still count for exponent */\n if (hasdot) e--; /* decimal digit? correct exponent */\n } else break; /* neither a dot nor a digit */\n }\n\n if (nosigdig + sigdig === 0) /* no digits? */\n return null; /* invalid format */\n e *= 4; /* each digit multiplies/divides value by 2^4 */\n if (s[i] === 112 /* ('p').charCodeAt(0) */ || s[i] === 80 /* ('P').charCodeAt(0) */) { /* exponent part? */\n let exp1 = 0; /* exponent value */\n let neg1; /* exponent signal */\n i++; /* skip 'p' */\n if ((neg1 = (s[i] === 45 /* ('-').charCodeAt(0) */))) i++; /* signal */\n else if (s[i] === 43 /* ('+').charCodeAt(0) */) i++;\n if (!lisdigit(s[i]))\n return null; /* invalid; must have at least one digit */\n while (lisdigit(s[i])) /* read exponent */\n exp1 = exp1 * 10 + s[i++] - 48 /* ('0').charCodeAt(0) */;\n if (neg1) exp1 = -exp1;\n e += exp1;\n }\n if (neg) r = -r;\n return {\n n: ldexp(r, e),\n i: i\n };\n};\n\nconst lua_str2number = function(s) {\n try {\n s = to_jsstring(s);\n } catch (e) {\n return null;\n }\n /* use a regex to validate number and also to get length\n parseFloat ignores trailing junk */\n let r = /^[\\t\\v\\f \\n\\r]*[+-]?(?:[0-9]+\\.?[0-9]*|\\.[0-9]*)(?:[eE][+-]?[0-9]+)?/.exec(s);\n if (!r)\n return null;\n let flt = parseFloat(r[0]);\n return !isNaN(flt) ? { n: flt, i: r[0].length } : null;\n};\n\nconst l_str2dloc = function(s, mode) {\n let result = mode === 'x' ? lua_strx2number(s) : lua_str2number(s); /* try to convert */\n if (result === null) return null;\n while (lisspace(s[result.i])) result.i++; /* skip trailing spaces */\n return (result.i === s.length || s[result.i] === 0) ? result : null; /* OK if no trailing characters */\n};\n\nconst SIGILS = [\n 46 /* (\".\").charCodeAt(0) */,\n 120 /* (\"x\").charCodeAt(0) */,\n 88 /* (\"X\").charCodeAt(0) */,\n 110 /* (\"n\").charCodeAt(0) */,\n 78 /* (\"N\").charCodeAt(0) */\n];\nconst modes = {\n [ 46]: \".\",\n [120]: \"x\",\n [ 88]: \"x\",\n [110]: \"n\",\n [ 78]: \"n\"\n};\nconst l_str2d = function(s) {\n let l = s.length;\n let pmode = 0;\n for (let i=0; i= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */\n return null; /* do not accept it (as integer) */\n a = (a * 10 + d)|0;\n empty = false;\n }\n }\n while (i < s.length && lisspace(s[i])) i++; /* skip trailing spaces */\n if (empty || (i !== s.length && s[i] !== 0)) return null; /* something wrong in the numeral */\n else {\n return {\n n: (neg ? -a : a)|0,\n i: i\n };\n }\n};\n\nconst luaO_str2num = function(s, o) {\n let s2i = l_str2int(s);\n if (s2i !== null) { /* try as an integer */\n o.setivalue(s2i.n);\n return s2i.i+1;\n } else { /* else try as a float */\n s2i = l_str2d(s);\n if (s2i !== null) {\n o.setfltvalue(s2i.n);\n return s2i.i+1;\n } else\n return 0; /* conversion failed */\n }\n};\n\nconst luaO_tostring = function(L, obj) {\n let buff;\n if (obj.ttisinteger())\n buff = to_luastring(lua_integer2str(obj.value));\n else {\n let str = lua_number2str(obj.value);\n if (!LUA_COMPAT_FLOATSTRING && /^[-0123456789]+$/.test(str)) { /* looks like an int? */\n str += '.0'; /* adds '.0' to result: lua_getlocaledecpoint removed as optimisation */\n }\n buff = to_luastring(str);\n }\n obj.setsvalue(luaS_bless(L, buff));\n};\n\nconst pushstr = function(L, str) {\n ldo.luaD_inctop(L);\n setsvalue2s(L, L.top-1, luaS_new(L, str));\n};\n\nconst luaO_pushvfstring = function(L, fmt, argp) {\n let n = 0;\n let i = 0;\n let a = 0;\n let e;\n for (;;) {\n e = luastring_indexOf(fmt, 37 /* ('%').charCodeAt(0) */, i);\n if (e == -1) break;\n pushstr(L, fmt.subarray(i, e));\n switch(fmt[e+1]) {\n case 115 /* ('s').charCodeAt(0) */: {\n let s = argp[a++];\n if (s === null) s = to_luastring(\"(null)\", true);\n else {\n s = from_userstring(s);\n /* respect null terminator */\n let i = luastring_indexOf(s, 0);\n if (i !== -1)\n s = s.subarray(0, i);\n }\n pushstr(L, s);\n break;\n }\n case 99 /* ('c').charCodeAt(0) */: {\n let buff = argp[a++];\n if (lisprint(buff))\n pushstr(L, luastring_of(buff));\n else\n luaO_pushfstring(L, to_luastring(\"<\\\\%d>\", true), buff);\n break;\n }\n case 100 /* ('d').charCodeAt(0) */:\n case 73 /* ('I').charCodeAt(0) */:\n ldo.luaD_inctop(L);\n L.stack[L.top-1].setivalue(argp[a++]);\n luaO_tostring(L, L.stack[L.top-1]);\n break;\n case 102 /* ('f').charCodeAt(0) */:\n ldo.luaD_inctop(L);\n L.stack[L.top-1].setfltvalue(argp[a++]);\n luaO_tostring(L, L.stack[L.top-1]);\n break;\n case 112 /* ('p').charCodeAt(0) */: {\n let v = argp[a++];\n if (v instanceof lstate.lua_State ||\n v instanceof ltable.Table ||\n v instanceof Udata ||\n v instanceof LClosure ||\n v instanceof CClosure) {\n pushstr(L, to_luastring(\"0x\"+v.id.toString(16)));\n } else {\n switch(typeof v) {\n case \"undefined\":\n pushstr(L, to_luastring(\"undefined\"));\n break;\n case \"number\": /* before check object as null is an object */\n pushstr(L, to_luastring(\"Number(\"+v+\")\"));\n break;\n case \"string\": /* before check object as null is an object */\n pushstr(L, to_luastring(\"String(\"+JSON.stringify(v)+\")\"));\n break;\n case \"boolean\": /* before check object as null is an object */\n pushstr(L, to_luastring(v?\"Boolean(true)\":\"Boolean(false)\"));\n break;\n case \"object\":\n if (v === null) { /* null is special */\n pushstr(L, to_luastring(\"null\"));\n break;\n }\n /* fall through */\n case \"function\": {\n let id = L.l_G.ids.get(v);\n if (!id) {\n id = L.l_G.id_counter++;\n L.l_G.ids.set(v, id);\n }\n pushstr(L, to_luastring(\"0x\"+id.toString(16)));\n break;\n }\n default:\n /* user provided object. no id available */\n pushstr(L, to_luastring(\"\"));\n }\n }\n break;\n }\n case 85 /* ('U').charCodeAt(0) */: {\n let buff = new Uint8Array(UTF8BUFFSZ);\n let l = luaO_utf8esc(buff, argp[a++]);\n pushstr(L, buff.subarray(UTF8BUFFSZ - l));\n break;\n }\n case 37 /* ('%').charCodeAt(0) */:\n pushstr(L, to_luastring(\"%\", true));\n break;\n default:\n ldebug.luaG_runerror(L, to_luastring(\"invalid option '%%%c' to 'lua_pushfstring'\"), fmt[e + 1]);\n }\n n += 2;\n i = e + 2;\n }\n ldo.luaD_checkstack(L, 1);\n pushstr(L, fmt.subarray(i));\n if (n > 0) lvm.luaV_concat(L, n+1);\n return L.stack[L.top-1].svalue();\n};\n\nconst luaO_pushfstring = function(L, fmt, ...argp) {\n return luaO_pushvfstring(L, fmt, argp);\n};\n\n\n/*\n** converts an integer to a \"floating point byte\", represented as\n** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if\n** eeeee !== 0 and (xxx) otherwise.\n*/\nconst luaO_int2fb = function(x) {\n let e = 0; /* exponent */\n if (x < 8) return x;\n while (x >= (8 << 4)) { /* coarse steps */\n x = (x + 0xf) >> 4; /* x = ceil(x / 16) */\n e += 4;\n }\n while (x >= (8 << 1)) { /* fine steps */\n x = (x + 1) >> 1; /* x = ceil(x / 2) */\n e++;\n }\n return ((e+1) << 3) | (x - 8);\n};\n\nconst intarith = function(L, op, v1, v2) {\n switch (op) {\n case LUA_OPADD: return (v1 + v2)|0;\n case LUA_OPSUB: return (v1 - v2)|0;\n case LUA_OPMUL: return lvm.luaV_imul(v1, v2);\n case LUA_OPMOD: return lvm.luaV_mod(L, v1, v2);\n case LUA_OPIDIV: return lvm.luaV_div(L, v1, v2);\n case LUA_OPBAND: return (v1 & v2);\n case LUA_OPBOR: return (v1 | v2);\n case LUA_OPBXOR: return (v1 ^ v2);\n case LUA_OPSHL: return lvm.luaV_shiftl(v1, v2);\n case LUA_OPSHR: return lvm.luaV_shiftl(v1, -v2);\n case LUA_OPUNM: return (0 - v1)|0;\n case LUA_OPBNOT: return (~0 ^ v1);\n default: lua_assert(0);\n }\n};\n\n\nconst numarith = function(L, op, v1, v2) {\n switch (op) {\n case LUA_OPADD: return v1 + v2;\n case LUA_OPSUB: return v1 - v2;\n case LUA_OPMUL: return v1 * v2;\n case LUA_OPDIV: return v1 / v2;\n case LUA_OPPOW: return Math.pow(v1, v2);\n case LUA_OPIDIV: return Math.floor(v1 / v2);\n case LUA_OPUNM: return -v1;\n case LUA_OPMOD: return luai_nummod(L, v1, v2);\n default: lua_assert(0);\n }\n};\n\nconst luaO_arith = function(L, op, p1, p2, p3) {\n let res = (typeof p3 === \"number\") ? L.stack[p3] : p3; /* FIXME */\n\n switch (op) {\n case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:\n case LUA_OPSHL: case LUA_OPSHR:\n case LUA_OPBNOT: { /* operate only on integers */\n let i1, i2;\n if ((i1 = lvm.tointeger(p1)) !== false && (i2 = lvm.tointeger(p2)) !== false) {\n res.setivalue(intarith(L, op, i1, i2));\n return;\n }\n else break; /* go to the end */\n }\n case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */\n let n1, n2;\n if ((n1 = lvm.tonumber(p1)) !== false && (n2 = lvm.tonumber(p2)) !== false) {\n res.setfltvalue(numarith(L, op, n1, n2));\n return;\n }\n else break; /* go to the end */\n }\n default: { /* other operations */\n let n1, n2;\n if (p1.ttisinteger() && p2.ttisinteger()) {\n res.setivalue(intarith(L, op, p1.value, p2.value));\n return;\n }\n else if ((n1 = lvm.tonumber(p1)) !== false && (n2 = lvm.tonumber(p2)) !== false) {\n res.setfltvalue(numarith(L, op, n1, n2));\n return;\n }\n else break; /* go to the end */\n }\n }\n /* could not perform raw operation; try metamethod */\n lua_assert(L !== null); /* should not fail when folding (compile time) */\n ltm.luaT_trybinTM(L, p1, p2, p3, (op - LUA_OPADD) + ltm.TMS.TM_ADD);\n};\n\n\nmodule.exports.CClosure = CClosure;\nmodule.exports.LClosure = LClosure;\nmodule.exports.LUA_TDEADKEY = LUA_TDEADKEY;\nmodule.exports.LUA_TPROTO = LUA_TPROTO;\nmodule.exports.LocVar = LocVar;\nmodule.exports.TValue = TValue;\nmodule.exports.Udata = Udata;\nmodule.exports.UTF8BUFFSZ = UTF8BUFFSZ;\nmodule.exports.luaO_arith = luaO_arith;\nmodule.exports.luaO_chunkid = luaO_chunkid;\nmodule.exports.luaO_hexavalue = luaO_hexavalue;\nmodule.exports.luaO_int2fb = luaO_int2fb;\nmodule.exports.luaO_pushfstring = luaO_pushfstring;\nmodule.exports.luaO_pushvfstring = luaO_pushvfstring;\nmodule.exports.luaO_str2num = luaO_str2num;\nmodule.exports.luaO_tostring = luaO_tostring;\nmodule.exports.luaO_utf8esc = luaO_utf8esc;\nmodule.exports.numarith = numarith;\nmodule.exports.pushobj2s = pushobj2s;\nmodule.exports.pushsvalue2s = pushsvalue2s;\nmodule.exports.setobjs2s = setobjs2s;\nmodule.exports.setobj2s = setobj2s;\nmodule.exports.setsvalue2s = setsvalue2s;\n","\"use strict\";\n\nconst {\n LUAL_BUFFERSIZE\n} = require('./luaconf.js');\nconst {\n LUA_ERRERR,\n LUA_MULTRET,\n LUA_REGISTRYINDEX,\n LUA_SIGNATURE,\n LUA_TBOOLEAN,\n LUA_TLIGHTUSERDATA,\n LUA_TNIL,\n LUA_TNONE,\n LUA_TNUMBER,\n LUA_TSTRING,\n LUA_TTABLE,\n LUA_VERSION_NUM,\n lua_Debug,\n lua_absindex,\n lua_atpanic,\n lua_call,\n lua_checkstack,\n lua_concat,\n lua_copy,\n lua_createtable,\n lua_error,\n lua_getfield,\n lua_getinfo,\n lua_getmetatable,\n lua_getstack,\n lua_gettop,\n lua_insert,\n lua_isinteger,\n lua_isnil,\n lua_isnumber,\n lua_isstring,\n lua_istable,\n lua_len,\n lua_load,\n lua_newstate,\n lua_newtable,\n lua_next,\n lua_pcall,\n lua_pop,\n lua_pushboolean,\n lua_pushcclosure,\n lua_pushcfunction,\n lua_pushfstring,\n lua_pushinteger,\n lua_pushliteral,\n lua_pushlstring,\n lua_pushnil,\n lua_pushstring,\n lua_pushvalue,\n lua_pushvfstring,\n lua_rawequal,\n lua_rawget,\n lua_rawgeti,\n lua_rawlen,\n lua_rawseti,\n lua_remove,\n lua_setfield,\n lua_setglobal,\n lua_setmetatable,\n lua_settop,\n lua_toboolean,\n lua_tointeger,\n lua_tointegerx,\n lua_tojsstring,\n lua_tolstring,\n lua_tonumber,\n lua_tonumberx,\n lua_topointer,\n lua_tostring,\n lua_touserdata,\n lua_type,\n lua_typename,\n lua_version\n} = require('./lua.js');\nconst {\n from_userstring,\n luastring_eq,\n to_luastring,\n to_uristring\n} = require(\"./fengaricore.js\");\n\n/* extra error code for 'luaL_loadfilex' */\nconst LUA_ERRFILE = LUA_ERRERR+1;\n\n/* key, in the registry, for table of loaded modules */\nconst LUA_LOADED_TABLE = to_luastring(\"_LOADED\");\n\n/* key, in the registry, for table of preloaded loaders */\nconst LUA_PRELOAD_TABLE = to_luastring(\"_PRELOAD\");\n\nconst LUA_FILEHANDLE = to_luastring(\"FILE*\");\n\nconst LUAL_NUMSIZES = 4*16 + 8;\n\nconst __name = to_luastring(\"__name\");\nconst __tostring = to_luastring(\"__tostring\");\n\nconst empty = new Uint8Array(0);\n\nclass luaL_Buffer {\n constructor() {\n this.L = null;\n this.b = empty;\n this.n = 0;\n }\n}\n\nconst LEVELS1 = 10; /* size of the first part of the stack */\nconst LEVELS2 = 11; /* size of the second part of the stack */\n\n/*\n** search for 'objidx' in table at index -1.\n** return 1 + string at top if find a good name.\n*/\nconst findfield = function(L, objidx, level) {\n if (level === 0 || !lua_istable(L, -1))\n return 0; /* not found */\n\n lua_pushnil(L); /* start 'next' loop */\n\n while (lua_next(L, -2)) { /* for each pair in table */\n if (lua_type(L, -2) === LUA_TSTRING) { /* ignore non-string keys */\n if (lua_rawequal(L, objidx, -1)) { /* found object? */\n lua_pop(L, 1); /* remove value (but keep name) */\n return 1;\n } else if (findfield(L, objidx, level - 1)) { /* try recursively */\n lua_remove(L, -2); /* remove table (but keep name) */\n lua_pushliteral(L, \".\");\n lua_insert(L, -2); /* place '.' between the two names */\n lua_concat(L, 3);\n return 1;\n }\n }\n lua_pop(L, 1); /* remove value */\n }\n\n return 0; /* not found */\n};\n\n/*\n** Search for a name for a function in all loaded modules\n*/\nconst pushglobalfuncname = function(L, ar) {\n let top = lua_gettop(L);\n lua_getinfo(L, to_luastring(\"f\"), ar); /* push function */\n lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);\n if (findfield(L, top + 1, 2)) {\n let name = lua_tostring(L, -1);\n if (name[0] === 95 /* '_'.charCodeAt(0) */ &&\n name[1] === 71 /* 'G'.charCodeAt(0) */ &&\n name[2] === 46 /* '.'.charCodeAt(0) */\n ) { /* name start with '_G.'? */\n lua_pushstring(L, name.subarray(3)); /* push name without prefix */\n lua_remove(L, -2); /* remove original name */\n }\n lua_copy(L, -1, top + 1); /* move name to proper place */\n lua_pop(L, 2); /* remove pushed values */\n return 1;\n } else {\n lua_settop(L, top); /* remove function and global table */\n return 0;\n }\n};\n\nconst pushfuncname = function(L, ar) {\n if (pushglobalfuncname(L, ar)) { /* try first a global name */\n lua_pushfstring(L, to_luastring(\"function '%s'\"), lua_tostring(L, -1));\n lua_remove(L, -2); /* remove name */\n }\n else if (ar.namewhat.length !== 0) /* is there a name from code? */\n lua_pushfstring(L, to_luastring(\"%s '%s'\"), ar.namewhat, ar.name); /* use it */\n else if (ar.what && ar.what[0] === 109 /* 'm'.charCodeAt(0) */) /* main? */\n lua_pushliteral(L, \"main chunk\");\n else if (ar.what && ar.what[0] === 76 /* 'L'.charCodeAt(0) */) /* for Lua functions, use */\n lua_pushfstring(L, to_luastring(\"function <%s:%d>\"), ar.short_src, ar.linedefined);\n else /* nothing left... */\n lua_pushliteral(L, \"?\");\n};\n\nconst lastlevel = function(L) {\n let ar = new lua_Debug();\n let li = 1;\n let le = 1;\n /* find an upper bound */\n while (lua_getstack(L, le, ar)) { li = le; le *= 2; }\n /* do a binary search */\n while (li < le) {\n let m = Math.floor((li + le)/2);\n if (lua_getstack(L, m, ar)) li = m + 1;\n else le = m;\n }\n return le - 1;\n};\n\nconst luaL_traceback = function(L, L1, msg, level) {\n let ar = new lua_Debug();\n let top = lua_gettop(L);\n let last = lastlevel(L1);\n let n1 = last - level > LEVELS1 + LEVELS2 ? LEVELS1 : -1;\n if (msg)\n lua_pushfstring(L, to_luastring(\"%s\\n\"), msg);\n luaL_checkstack(L, 10, null);\n lua_pushliteral(L, \"stack traceback:\");\n while (lua_getstack(L1, level++, ar)) {\n if (n1-- === 0) { /* too many levels? */\n lua_pushliteral(L, \"\\n\\t...\"); /* add a '...' */\n level = last - LEVELS2 + 1; /* and skip to last ones */\n } else {\n lua_getinfo(L1, to_luastring(\"Slnt\", true), ar);\n lua_pushfstring(L, to_luastring(\"\\n\\t%s:\"), ar.short_src);\n if (ar.currentline > 0)\n lua_pushliteral(L, `${ar.currentline}:`);\n lua_pushliteral(L, \" in \");\n pushfuncname(L, ar);\n if (ar.istailcall)\n lua_pushliteral(L, \"\\n\\t(...tail calls..)\");\n lua_concat(L, lua_gettop(L) - top);\n }\n }\n lua_concat(L, lua_gettop(L) - top);\n};\n\nconst panic = function(L) {\n let msg = \"PANIC: unprotected error in call to Lua API (\" + lua_tojsstring(L, -1) + \")\";\n throw new Error(msg);\n};\n\nconst luaL_argerror = function(L, arg, extramsg) {\n let ar = new lua_Debug();\n\n if (!lua_getstack(L, 0, ar)) /* no stack frame? */\n return luaL_error(L, to_luastring(\"bad argument #%d (%s)\"), arg, extramsg);\n\n lua_getinfo(L, to_luastring(\"n\"), ar);\n\n if (luastring_eq(ar.namewhat, to_luastring(\"method\"))) {\n arg--; /* do not count 'self' */\n if (arg === 0) /* error is in the self argument itself? */\n return luaL_error(L, to_luastring(\"calling '%s' on bad self (%s)\"), ar.name, extramsg);\n }\n\n if (ar.name === null)\n ar.name = pushglobalfuncname(L, ar) ? lua_tostring(L, -1) : to_luastring(\"?\");\n\n return luaL_error(L, to_luastring(\"bad argument #%d to '%s' (%s)\"), arg, ar.name, extramsg);\n};\n\nconst typeerror = function(L, arg, tname) {\n let typearg;\n if (luaL_getmetafield(L, arg, __name) === LUA_TSTRING)\n typearg = lua_tostring(L, -1);\n else if (lua_type(L, arg) === LUA_TLIGHTUSERDATA)\n typearg = to_luastring(\"light userdata\", true);\n else\n typearg = luaL_typename(L, arg);\n\n let msg = lua_pushfstring(L, to_luastring(\"%s expected, got %s\"), tname, typearg);\n return luaL_argerror(L, arg, msg);\n};\n\nconst luaL_where = function(L, level) {\n let ar = new lua_Debug();\n if (lua_getstack(L, level, ar)) {\n lua_getinfo(L, to_luastring(\"Sl\", true), ar);\n if (ar.currentline > 0) {\n lua_pushfstring(L, to_luastring(\"%s:%d: \"), ar.short_src, ar.currentline);\n return;\n }\n }\n lua_pushstring(L, to_luastring(\"\"));\n};\n\nconst luaL_error = function(L, fmt, ...argp) {\n luaL_where(L, 1);\n lua_pushvfstring(L, fmt, argp);\n lua_concat(L, 2);\n return lua_error(L);\n};\n\n/* Unlike normal lua, we pass in an error object */\nconst luaL_fileresult = function(L, stat, fname, e) {\n if (stat) {\n lua_pushboolean(L, 1);\n return 1;\n } else {\n lua_pushnil(L);\n let message, errno;\n if (e) {\n message = e.message;\n errno = -e.errno;\n } else {\n message = \"Success\"; /* what strerror(0) returns */\n errno = 0;\n }\n if (fname)\n lua_pushfstring(L, to_luastring(\"%s: %s\"), fname, to_luastring(message));\n else\n lua_pushstring(L, to_luastring(message));\n lua_pushinteger(L, errno);\n return 3;\n }\n};\n\n/* Unlike normal lua, we pass in an error object */\nconst luaL_execresult = function(L, e) {\n let what, stat;\n if (e === null) {\n lua_pushboolean(L, 1);\n lua_pushliteral(L, \"exit\");\n lua_pushinteger(L, 0);\n return 3;\n } else if (e.status) {\n what = \"exit\";\n stat = e.status;\n } else if (e.signal) {\n what = \"signal\";\n stat = e.signal;\n } else {\n /* XXX: node seems to have e.errno as a string instead of a number */\n return luaL_fileresult(L, 0, null, e);\n }\n lua_pushnil(L);\n lua_pushliteral(L, what);\n lua_pushinteger(L, stat);\n return 3;\n};\n\nconst luaL_getmetatable = function(L, n) {\n return lua_getfield(L, LUA_REGISTRYINDEX, n);\n};\n\nconst luaL_newmetatable = function(L, tname) {\n if (luaL_getmetatable(L, tname) !== LUA_TNIL) /* name already in use? */\n return 0; /* leave previous value on top, but return 0 */\n lua_pop(L, 1);\n lua_createtable(L, 0, 2); /* create metatable */\n lua_pushstring(L, tname);\n lua_setfield(L, -2, __name); /* metatable.__name = tname */\n lua_pushvalue(L, -1);\n lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */\n return 1;\n\n};\n\nconst luaL_setmetatable = function(L, tname) {\n luaL_getmetatable(L, tname);\n lua_setmetatable(L, -2);\n};\n\nconst luaL_testudata = function(L, ud, tname) {\n let p = lua_touserdata(L, ud);\n if (p !== null) { /* value is a userdata? */\n if (lua_getmetatable(L, ud)) { /* does it have a metatable? */\n luaL_getmetatable(L, tname); /* get correct metatable */\n if (!lua_rawequal(L, -1, -2)) /* not the same? */\n p = null; /* value is a userdata with wrong metatable */\n lua_pop(L, 2); /* remove both metatables */\n return p;\n }\n }\n return null; /* value is not a userdata with a metatable */\n};\n\nconst luaL_checkudata = function(L, ud, tname) {\n let p = luaL_testudata(L, ud, tname);\n if (p === null) typeerror(L, ud, tname);\n return p;\n};\n\nconst luaL_checkoption = function(L, arg, def, lst) {\n let name = def !== null ? luaL_optstring(L, arg, def) : luaL_checkstring(L, arg);\n for (let i = 0; lst[i]; i++)\n if (luastring_eq(lst[i], name))\n return i;\n return luaL_argerror(L, arg, lua_pushfstring(L, to_luastring(\"invalid option '%s'\"), name));\n};\n\nconst tag_error = function(L, arg, tag) {\n typeerror(L, arg, lua_typename(L, tag));\n};\n\nconst luaL_newstate = function() {\n let L = lua_newstate();\n if (L) lua_atpanic(L, panic);\n return L;\n};\n\n\nconst luaL_typename = function(L, i) {\n return lua_typename(L, lua_type(L, i));\n};\n\nconst luaL_argcheck = function(L, cond, arg, extramsg) {\n if (!cond) luaL_argerror(L, arg, extramsg);\n};\n\nconst luaL_checkany = function(L, arg) {\n if (lua_type(L, arg) === LUA_TNONE)\n luaL_argerror(L, arg, to_luastring(\"value expected\", true));\n};\n\nconst luaL_checktype = function(L, arg, t) {\n if (lua_type(L, arg) !== t)\n tag_error(L, arg, t);\n};\n\nconst luaL_checklstring = function(L, arg) {\n let s = lua_tolstring(L, arg);\n if (s === null || s === undefined) tag_error(L, arg, LUA_TSTRING);\n return s;\n};\n\nconst luaL_checkstring = luaL_checklstring;\n\nconst luaL_optlstring = function(L, arg, def) {\n if (lua_type(L, arg) <= 0) {\n return def === null ? null : from_userstring(def);\n } else return luaL_checklstring(L, arg);\n};\n\nconst luaL_optstring = luaL_optlstring;\n\nconst interror = function(L, arg) {\n if (lua_isnumber(L, arg))\n luaL_argerror(L, arg, to_luastring(\"number has no integer representation\", true));\n else\n tag_error(L, arg, LUA_TNUMBER);\n};\n\nconst luaL_checknumber = function(L, arg) {\n let d = lua_tonumberx(L, arg);\n if (d === false)\n tag_error(L, arg, LUA_TNUMBER);\n return d;\n};\n\nconst luaL_optnumber = function(L, arg, def) {\n return luaL_opt(L, luaL_checknumber, arg, def);\n};\n\nconst luaL_checkinteger = function(L, arg) {\n let d = lua_tointegerx(L, arg);\n if (d === false)\n interror(L, arg);\n return d;\n};\n\nconst luaL_optinteger = function(L, arg, def) {\n return luaL_opt(L, luaL_checkinteger, arg, def);\n};\n\nconst luaL_prepbuffsize = function(B, sz) {\n let newend = B.n + sz;\n if (B.b.length < newend) {\n let newsize = Math.max(B.b.length * 2, newend); /* double buffer size */\n let newbuff = new Uint8Array(newsize); /* create larger buffer */\n newbuff.set(B.b); /* copy original content */\n B.b = newbuff;\n }\n return B.b.subarray(B.n, newend);\n};\n\nconst luaL_buffinit = function(L, B) {\n B.L = L;\n B.b = empty;\n};\n\nconst luaL_buffinitsize = function(L, B, sz) {\n luaL_buffinit(L, B);\n return luaL_prepbuffsize(B, sz);\n};\n\nconst luaL_prepbuffer = function(B) {\n return luaL_prepbuffsize(B, LUAL_BUFFERSIZE);\n};\n\nconst luaL_addlstring = function(B, s, l) {\n if (l > 0) {\n s = from_userstring(s);\n let b = luaL_prepbuffsize(B, l);\n b.set(s.subarray(0, l));\n luaL_addsize(B, l);\n }\n};\n\nconst luaL_addstring = function(B, s) {\n s = from_userstring(s);\n luaL_addlstring(B, s, s.length);\n};\n\nconst luaL_pushresult = function(B) {\n lua_pushlstring(B.L, B.b, B.n);\n /* delete old buffer */\n B.n = 0;\n B.b = empty;\n};\n\nconst luaL_addchar = function(B, c) {\n luaL_prepbuffsize(B, 1);\n B.b[B.n++] = c;\n};\n\nconst luaL_addsize = function(B, s) {\n B.n += s;\n};\n\nconst luaL_pushresultsize = function(B, sz) {\n luaL_addsize(B, sz);\n luaL_pushresult(B);\n};\n\nconst luaL_addvalue = function(B) {\n let L = B.L;\n let s = lua_tostring(L, -1);\n luaL_addlstring(B, s, s.length);\n lua_pop(L, 1); /* remove value */\n};\n\nconst luaL_opt = function(L, f, n, d) {\n return lua_type(L, n) <= 0 ? d : f(L, n);\n};\n\nconst getS = function(L, ud) {\n let s = ud.string;\n ud.string = null;\n return s;\n};\n\nconst luaL_loadbufferx = function(L, buff, size, name, mode) {\n return lua_load(L, getS, {string: buff}, name, mode);\n};\n\nconst luaL_loadbuffer = function(L, s, sz, n) {\n return luaL_loadbufferx(L, s, sz, n, null);\n};\n\nconst luaL_loadstring = function(L, s) {\n return luaL_loadbuffer(L, s, s.length, s);\n};\n\nconst luaL_dostring = function(L, s) {\n return (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0));\n};\n\nconst luaL_getmetafield = function(L, obj, event) {\n if (!lua_getmetatable(L, obj)) /* no metatable? */\n return LUA_TNIL;\n else {\n lua_pushstring(L, event);\n let tt = lua_rawget(L, -2);\n if (tt === LUA_TNIL) /* is metafield nil? */\n lua_pop(L, 2); /* remove metatable and metafield */\n else\n lua_remove(L, -2); /* remove only metatable */\n return tt; /* return metafield type */\n }\n};\n\nconst luaL_callmeta = function(L, obj, event) {\n obj = lua_absindex(L, obj);\n if (luaL_getmetafield(L, obj, event) === LUA_TNIL)\n return false;\n\n lua_pushvalue(L, obj);\n lua_call(L, 1, 1);\n\n return true;\n};\n\nconst luaL_len = function(L, idx) {\n lua_len(L, idx);\n let l = lua_tointegerx(L, -1);\n if (l === false)\n luaL_error(L, to_luastring(\"object length is not an integer\", true));\n lua_pop(L, 1); /* remove object */\n return l;\n};\n\nconst p_I = to_luastring(\"%I\");\nconst p_f = to_luastring(\"%f\");\nconst luaL_tolstring = function(L, idx) {\n if (luaL_callmeta(L, idx, __tostring)) {\n if (!lua_isstring(L, -1))\n luaL_error(L, to_luastring(\"'__tostring' must return a string\"));\n } else {\n let t = lua_type(L, idx);\n switch(t) {\n case LUA_TNUMBER: {\n if (lua_isinteger(L, idx))\n lua_pushfstring(L, p_I, lua_tointeger(L, idx));\n else\n lua_pushfstring(L, p_f, lua_tonumber(L, idx));\n break;\n }\n case LUA_TSTRING:\n lua_pushvalue(L, idx);\n break;\n case LUA_TBOOLEAN:\n lua_pushliteral(L, (lua_toboolean(L, idx) ? \"true\" : \"false\"));\n break;\n case LUA_TNIL:\n lua_pushliteral(L, \"nil\");\n break;\n default: {\n let tt = luaL_getmetafield(L, idx, __name);\n let kind = tt === LUA_TSTRING ? lua_tostring(L, -1) : luaL_typename(L, idx);\n lua_pushfstring(L, to_luastring(\"%s: %p\"), kind, lua_topointer(L, idx));\n if (tt !== LUA_TNIL)\n lua_remove(L, -2);\n break;\n }\n }\n }\n\n return lua_tolstring(L, -1);\n};\n\n/*\n** Stripped-down 'require': After checking \"loaded\" table, calls 'openf'\n** to open a module, registers the result in 'package.loaded' table and,\n** if 'glb' is true, also registers the result in the global table.\n** Leaves resulting module on the top.\n*/\nconst luaL_requiref = function(L, modname, openf, glb) {\n luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);\n lua_getfield(L, -1, modname); /* LOADED[modname] */\n if (!lua_toboolean(L, -1)) { /* package not already loaded? */\n lua_pop(L, 1); /* remove field */\n lua_pushcfunction(L, openf);\n lua_pushstring(L, modname); /* argument to open function */\n lua_call(L, 1, 1); /* call 'openf' to open module */\n lua_pushvalue(L, -1); /* make copy of module (call result) */\n lua_setfield(L, -3, modname); /* LOADED[modname] = module */\n }\n lua_remove(L, -2); /* remove LOADED table */\n if (glb) {\n lua_pushvalue(L, -1); /* copy of module */\n lua_setglobal(L, modname); /* _G[modname] = module */\n }\n};\n\nconst find_subarray = function(arr, subarr, from_index) {\n var i = from_index >>> 0,\n sl = subarr.length,\n l = arr.length + 1 - sl;\n\n loop: for (; i < l; i++) {\n for (let j = 0; j < sl; j++)\n if (arr[i+j] !== subarr[j])\n continue loop;\n return i;\n }\n return -1;\n};\n\nconst luaL_gsub = function(L, s, p, r) {\n let wild;\n let b = new luaL_Buffer();\n luaL_buffinit(L, b);\n while ((wild = find_subarray(s, p)) >= 0) {\n luaL_addlstring(b, s, wild); /* push prefix */\n luaL_addstring(b, r); /* push replacement in place of pattern */\n s = s.subarray(wild + p.length); /* continue after 'p' */\n }\n luaL_addstring(b, s); /* push last suffix */\n luaL_pushresult(b);\n return lua_tostring(L, -1);\n};\n\n/*\n** ensure that stack[idx][fname] has a table and push that table\n** into the stack\n*/\nconst luaL_getsubtable = function(L, idx, fname) {\n if (lua_getfield(L, idx, fname) === LUA_TTABLE)\n return true; /* table already there */\n else {\n lua_pop(L, 1); /* remove previous result */\n idx = lua_absindex(L, idx);\n lua_newtable(L);\n lua_pushvalue(L, -1); /* copy to be left at top */\n lua_setfield(L, idx, fname); /* assign new table to field */\n return false; /* false, because did not find table there */\n }\n};\n\n/*\n** set functions from list 'l' into table at top - 'nup'; each\n** function gets the 'nup' elements at the top as upvalues.\n** Returns with only the table at the stack.\n*/\nconst luaL_setfuncs = function(L, l, nup) {\n luaL_checkstack(L, nup, to_luastring(\"too many upvalues\", true));\n for (let lib in l) { /* fill the table with given functions */\n for (let i = 0; i < nup; i++) /* copy upvalues to the top */\n lua_pushvalue(L, -nup);\n lua_pushcclosure(L, l[lib], nup); /* closure with those upvalues */\n lua_setfield(L, -(nup + 2), to_luastring(lib));\n }\n lua_pop(L, nup); /* remove upvalues */\n};\n\n/*\n** Ensures the stack has at least 'space' extra slots, raising an error\n** if it cannot fulfill the request. (The error handling needs a few\n** extra slots to format the error message. In case of an error without\n** this extra space, Lua will generate the same 'stack overflow' error,\n** but without 'msg'.)\n*/\nconst luaL_checkstack = function(L, space, msg) {\n if (!lua_checkstack(L, space)) {\n if (msg)\n luaL_error(L, to_luastring(\"stack overflow (%s)\"), msg);\n else\n luaL_error(L, to_luastring('stack overflow', true));\n }\n};\n\nconst luaL_newlibtable = function(L) {\n lua_createtable(L);\n};\n\nconst luaL_newlib = function(L, l) {\n lua_createtable(L);\n luaL_setfuncs(L, l, 0);\n};\n\n/* predefined references */\nconst LUA_NOREF = -2;\nconst LUA_REFNIL = -1;\n\nconst luaL_ref = function(L, t) {\n let ref;\n if (lua_isnil(L, -1)) {\n lua_pop(L, 1); /* remove from stack */\n return LUA_REFNIL; /* 'nil' has a unique fixed reference */\n }\n t = lua_absindex(L, t);\n lua_rawgeti(L, t, 0); /* get first free element */\n ref = lua_tointeger(L, -1); /* ref = t[freelist] */\n lua_pop(L, 1); /* remove it from stack */\n if (ref !== 0) { /* any free element? */\n lua_rawgeti(L, t, ref); /* remove it from list */\n lua_rawseti(L, t, 0); /* (t[freelist] = t[ref]) */\n }\n else /* no free elements */\n ref = lua_rawlen(L, t) + 1; /* get a new reference */\n lua_rawseti(L, t, ref);\n return ref;\n};\n\n\nconst luaL_unref = function(L, t, ref) {\n if (ref >= 0) {\n t = lua_absindex(L, t);\n lua_rawgeti(L, t, 0);\n lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */\n lua_pushinteger(L, ref);\n lua_rawseti(L, t, 0); /* t[freelist] = ref */\n }\n};\n\n\nconst errfile = function(L, what, fnameindex, error) {\n let serr = error.message;\n let filename = lua_tostring(L, fnameindex).subarray(1);\n lua_pushfstring(L, to_luastring(\"cannot %s %s: %s\"), to_luastring(what), filename, to_luastring(serr));\n lua_remove(L, fnameindex);\n return LUA_ERRFILE;\n};\n\nlet getc;\n\nconst utf8_bom = [0XEF, 0XBB, 0XBF]; /* UTF-8 BOM mark */\nconst skipBOM = function(lf) {\n lf.n = 0;\n let c;\n let p = 0;\n do {\n c = getc(lf);\n if (c === null || c !== utf8_bom[p]) return c;\n p++;\n lf.buff[lf.n++] = c; /* to be read by the parser */\n } while (p < utf8_bom.length);\n lf.n = 0; /* prefix matched; discard it */\n return getc(lf); /* return next character */\n};\n\n/*\n** reads the first character of file 'f' and skips an optional BOM mark\n** in its beginning plus its first line if it starts with '#'. Returns\n** true if it skipped the first line. In any case, '*cp' has the\n** first \"valid\" character of the file (after the optional BOM and\n** a first-line comment).\n*/\nconst skipcomment = function(lf) {\n let c = skipBOM(lf);\n if (c === 35 /* '#'.charCodeAt(0) */) { /* first line is a comment (Unix exec. file)? */\n do { /* skip first line */\n c = getc(lf);\n } while (c && c !== 10 /* '\\n'.charCodeAt(0) */);\n\n return {\n skipped: true,\n c: getc(lf) /* skip end-of-line, if present */\n };\n } else {\n return {\n skipped: false,\n c: c\n };\n }\n};\n\nlet luaL_loadfilex;\n\nif (typeof process === \"undefined\") {\n class LoadF {\n constructor() {\n this.n = NaN; /* number of pre-read characters */\n this.f = null; /* file being read */\n this.buff = new Uint8Array(1024); /* area for reading file */\n this.pos = 0; /* current position in file */\n this.err = void 0;\n }\n }\n\n const getF = function(L, ud) {\n let lf = ud;\n\n if (lf.f !== null && lf.n > 0) { /* are there pre-read characters to be read? */\n let bytes = lf.n; /* return them (chars already in buffer) */\n lf.n = 0; /* no more pre-read characters */\n lf.f = lf.f.subarray(lf.pos); /* we won't use lf.buff anymore */\n return lf.buff.subarray(0, bytes);\n }\n\n let f = lf.f;\n lf.f = null;\n return f;\n };\n\n getc = function(lf) {\n return lf.pos < lf.f.length ? lf.f[lf.pos++] : null;\n };\n\n luaL_loadfilex = function(L, filename, mode) {\n let lf = new LoadF();\n let fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */\n if (filename === null) {\n throw new Error(\"Can't read stdin in the browser\");\n } else {\n lua_pushfstring(L, to_luastring(\"@%s\"), filename);\n let path = to_uristring(filename);\n let xhr = new XMLHttpRequest();\n xhr.open(\"GET\", path, false);\n /*\n Synchronous xhr in main thread always returns a js string.\n Some browsers make console noise if you even attempt to set responseType\n */\n if (typeof window === \"undefined\") {\n xhr.responseType = \"arraybuffer\";\n }\n xhr.send();\n if (xhr.status >= 200 && xhr.status <= 299) {\n if (typeof xhr.response === \"string\") {\n lf.f = to_luastring(xhr.response);\n } else {\n lf.f = new Uint8Array(xhr.response);\n }\n } else {\n lf.err = xhr.status;\n return errfile(L, \"open\", fnameindex, { message: `${xhr.status}: ${xhr.statusText}` });\n }\n }\n let com = skipcomment(lf);\n /* check for signature first, as we don't want to add line number corrections in binary case */\n if (com.c === LUA_SIGNATURE[0] && filename) { /* binary file? */\n /* no need to re-open */\n } else if (com.skipped) { /* read initial portion */\n lf.buff[lf.n++] = 10 /* '\\n'.charCodeAt(0) */; /* add line to correct line numbers */\n }\n if (com.c !== null)\n lf.buff[lf.n++] = com.c; /* 'c' is the first character of the stream */\n let status = lua_load(L, getF, lf, lua_tostring(L, -1), mode);\n let readstatus = lf.err;\n if (readstatus) {\n lua_settop(L, fnameindex); /* ignore results from 'lua_load' */\n return errfile(L, \"read\", fnameindex, readstatus);\n }\n lua_remove(L, fnameindex);\n return status;\n };\n} else {\n const fs = require('fs');\n\n class LoadF {\n constructor() {\n this.n = NaN; /* number of pre-read characters */\n this.f = null; /* file being read */\n this.buff = Buffer.alloc(1024); /* area for reading file */\n this.pos = 0; /* current position in file */\n this.err = void 0;\n }\n }\n\n const getF = function(L, ud) {\n let lf = ud;\n let bytes = 0;\n if (lf.n > 0) { /* are there pre-read characters to be read? */\n bytes = lf.n; /* return them (chars already in buffer) */\n lf.n = 0; /* no more pre-read characters */\n } else { /* read a block from file */\n try {\n bytes = fs.readSync(lf.f, lf.buff, 0, lf.buff.length, lf.pos); /* read block */\n } catch(e) {\n lf.err = e;\n bytes = 0;\n }\n lf.pos += bytes;\n }\n if (bytes > 0)\n return lf.buff.subarray(0, bytes);\n else return null;\n };\n\n getc = function(lf) {\n let b = Buffer.alloc(1);\n let bytes;\n try {\n bytes = fs.readSync(lf.f, b, 0, 1, lf.pos);\n } catch(e) {\n lf.err = e;\n return null;\n }\n lf.pos += bytes;\n return bytes > 0 ? b.readUInt8() : null;\n };\n\n luaL_loadfilex = function(L, filename, mode) {\n let lf = new LoadF();\n let fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */\n if (filename === null) {\n lua_pushliteral(L, \"=stdin\");\n lf.f = process.stdin.fd;\n } else {\n lua_pushfstring(L, to_luastring(\"@%s\"), filename);\n try {\n lf.f = fs.openSync(filename, \"r\");\n } catch (e) {\n return errfile(L, \"open\", fnameindex, e);\n }\n }\n let com = skipcomment(lf);\n /* check for signature first, as we don't want to add line number corrections in binary case */\n if (com.c === LUA_SIGNATURE[0] && filename) { /* binary file? */\n /* no need to re-open */\n } else if (com.skipped) { /* read initial portion */\n lf.buff[lf.n++] = 10 /* '\\n'.charCodeAt(0) */; /* add line to correct line numbers */\n }\n if (com.c !== null)\n lf.buff[lf.n++] = com.c; /* 'c' is the first character of the stream */\n let status = lua_load(L, getF, lf, lua_tostring(L, -1), mode);\n let readstatus = lf.err;\n if (filename) try { fs.closeSync(lf.f); } catch(e) {} /* close file (even in case of errors) */\n if (readstatus) {\n lua_settop(L, fnameindex); /* ignore results from 'lua_load' */\n return errfile(L, \"read\", fnameindex, readstatus);\n }\n lua_remove(L, fnameindex);\n return status;\n };\n}\n\nconst luaL_loadfile = function(L, filename) {\n return luaL_loadfilex(L, filename, null);\n};\n\nconst luaL_dofile = function(L, filename) {\n return (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0));\n};\n\nconst lua_writestringerror = function() {\n for (let i=0; i newtop)\n delete L.stack[--L.top];\n }\n};\n\nconst seterrorobj = function(L, errcode, oldtop) {\n let current_top = L.top;\n\n /* extend stack so that L.stack[oldtop] is sure to exist */\n while (L.top < oldtop + 1)\n L.stack[L.top++] = new lobject.TValue(LUA_TNIL, null);\n\n switch (errcode) {\n case LUA_ERRMEM: {\n lobject.setsvalue2s(L, oldtop, luaS_newliteral(L, \"not enough memory\"));\n break;\n }\n case LUA_ERRERR: {\n lobject.setsvalue2s(L, oldtop, luaS_newliteral(L, \"error in error handling\"));\n break;\n }\n default: {\n lobject.setobjs2s(L, oldtop, current_top - 1);\n }\n }\n\n while (L.top > oldtop + 1)\n delete L.stack[--L.top];\n};\n\nconst ERRORSTACKSIZE = LUAI_MAXSTACK + 200;\n\nconst luaD_reallocstack = function(L, newsize) {\n lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);\n lua_assert(L.stack_last == L.stack.length - lstate.EXTRA_STACK);\n L.stack.length = newsize;\n L.stack_last = newsize - lstate.EXTRA_STACK;\n};\n\nconst luaD_growstack = function(L, n) {\n let size = L.stack.length;\n if (size > LUAI_MAXSTACK)\n luaD_throw(L, LUA_ERRERR);\n else {\n let needed = L.top + n + lstate.EXTRA_STACK;\n let newsize = 2 * size;\n if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK;\n if (newsize < needed) newsize = needed;\n if (newsize > LUAI_MAXSTACK) { /* stack overflow? */\n luaD_reallocstack(L, ERRORSTACKSIZE);\n ldebug.luaG_runerror(L, to_luastring(\"stack overflow\", true));\n }\n else\n luaD_reallocstack(L, newsize);\n }\n};\n\nconst luaD_checkstack = function(L, n) {\n if (L.stack_last - L.top <= n)\n luaD_growstack(L, n);\n};\n\nconst stackinuse = function(L) {\n let lim = L.top;\n for (let ci = L.ci; ci !== null; ci = ci.previous) {\n if (lim < ci.top) lim = ci.top;\n }\n lua_assert(lim <= L.stack_last);\n return lim + 1; /* part of stack in use */\n};\n\nconst luaD_shrinkstack = function(L) {\n let inuse = stackinuse(L);\n let goodsize = inuse + Math.floor(inuse / 8) + 2*lstate.EXTRA_STACK;\n if (goodsize > LUAI_MAXSTACK)\n goodsize = LUAI_MAXSTACK; /* respect stack limit */\n if (L.stack.length > LUAI_MAXSTACK) /* had been handling stack overflow? */\n lstate.luaE_freeCI(L); /* free all CIs (list grew because of an error) */\n /* if thread is currently not handling a stack overflow and its\n good size is smaller than current size, shrink its stack */\n if (inuse <= (LUAI_MAXSTACK - lstate.EXTRA_STACK) && goodsize < L.stack.length)\n luaD_reallocstack(L, goodsize);\n};\n\nconst luaD_inctop = function(L) {\n luaD_checkstack(L, 1);\n L.stack[L.top++] = new lobject.TValue(LUA_TNIL, null);\n};\n\n/*\n** Prepares a function call: checks the stack, creates a new CallInfo\n** entry, fills in the relevant information, calls hook if needed.\n** If function is a JS function, does the call, too. (Otherwise, leave\n** the execution ('luaV_execute') to the caller, to allow stackless\n** calls.) Returns true iff function has been executed (JS function).\n*/\nconst luaD_precall = function(L, off, nresults) {\n let func = L.stack[off];\n\n switch(func.type) {\n case LUA_TCCL:\n case LUA_TLCF: {\n let f = func.type === LUA_TCCL ? func.value.f : func.value;\n\n luaD_checkstack(L, LUA_MINSTACK);\n let ci = lstate.luaE_extendCI(L);\n ci.funcOff = off;\n ci.nresults = nresults;\n ci.func = func;\n ci.top = L.top + LUA_MINSTACK;\n lua_assert(ci.top <= L.stack_last);\n ci.callstatus = 0;\n if (L.hookmask & LUA_MASKCALL)\n luaD_hook(L, LUA_HOOKCALL, -1);\n let n = f(L); /* do the actual call */\n if (typeof n !== \"number\" || n < 0 || (n|0) !== n)\n throw Error(\"invalid return value from JS function (expected integer)\");\n lapi.api_checknelems(L, n);\n\n luaD_poscall(L, ci, L.top - n, n);\n\n return true;\n }\n case LUA_TLCL: {\n let base;\n let p = func.value.p;\n let n = L.top - off - 1;\n let fsize = p.maxstacksize;\n luaD_checkstack(L, fsize);\n if (p.is_vararg) {\n base = adjust_varargs(L, p, n);\n } else {\n for (; n < p.numparams; n++)\n L.stack[L.top++] = new lobject.TValue(LUA_TNIL, null); // complete missing arguments\n base = off + 1;\n }\n\n let ci = lstate.luaE_extendCI(L);\n ci.funcOff = off;\n ci.nresults = nresults;\n ci.func = func;\n ci.l_base = base;\n ci.top = base + fsize;\n adjust_top(L, ci.top);\n ci.l_code = p.code;\n ci.l_savedpc = 0;\n ci.callstatus = lstate.CIST_LUA;\n if (L.hookmask & LUA_MASKCALL)\n callhook(L, ci);\n return false;\n }\n default:\n luaD_checkstack(L, 1);\n tryfuncTM(L, off, func);\n return luaD_precall(L, off, nresults);\n }\n};\n\nconst luaD_poscall = function(L, ci, firstResult, nres) {\n let wanted = ci.nresults;\n\n if (L.hookmask & (LUA_MASKRET | LUA_MASKLINE)) {\n if (L.hookmask & LUA_MASKRET)\n luaD_hook(L, LUA_HOOKRET, -1);\n L.oldpc = ci.previous.l_savedpc; /* 'oldpc' for caller function */\n }\n\n let res = ci.funcOff;\n L.ci = ci.previous;\n L.ci.next = null;\n return moveresults(L, firstResult, res, nres, wanted);\n};\n\nconst moveresults = function(L, firstResult, res, nres, wanted) {\n switch (wanted) {\n case 0:\n break;\n case 1: {\n if (nres === 0)\n L.stack[res].setnilvalue();\n else {\n lobject.setobjs2s(L, res, firstResult); /* move it to proper place */\n }\n break;\n }\n case LUA_MULTRET: {\n for (let i = 0; i < nres; i++)\n lobject.setobjs2s(L, res + i, firstResult + i);\n for (let i=L.top; i>=(res + nres); i--)\n delete L.stack[i];\n L.top = res + nres;\n return false;\n }\n default: {\n let i;\n if (wanted <= nres) {\n for (i = 0; i < wanted; i++)\n lobject.setobjs2s(L, res + i, firstResult + i);\n } else {\n for (i = 0; i < nres; i++)\n lobject.setobjs2s(L, res + i, firstResult + i);\n for (; i < wanted; i++) {\n if (res+i >= L.top)\n L.stack[res + i] = new lobject.TValue(LUA_TNIL, null);\n else\n L.stack[res + i].setnilvalue();\n }\n }\n break;\n }\n }\n let newtop = res + wanted; /* top points after the last result */\n for (let i=L.top; i>=newtop; i--)\n delete L.stack[i];\n L.top = newtop;\n return true;\n};\n\n/*\n** Call a hook for the given event. Make sure there is a hook to be\n** called. (Both 'L->hook' and 'L->hookmask', which triggers this\n** function, can be changed asynchronously by signals.)\n*/\nconst luaD_hook = function(L, event, line) {\n let hook = L.hook;\n if (hook && L.allowhook) { /* make sure there is a hook */\n let ci = L.ci;\n let top = L.top;\n let ci_top = ci.top;\n let ar = new lua_Debug();\n ar.event = event;\n ar.currentline = line;\n ar.i_ci = ci;\n luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */\n ci.top = L.top + LUA_MINSTACK;\n lua_assert(ci.top <= L.stack_last);\n L.allowhook = 0; /* cannot call hooks inside a hook */\n ci.callstatus |= lstate.CIST_HOOKED;\n hook(L, ar);\n lua_assert(!L.allowhook);\n L.allowhook = 1;\n ci.top = ci_top;\n adjust_top(L, top);\n ci.callstatus &= ~lstate.CIST_HOOKED;\n }\n};\n\nconst callhook = function(L, ci) {\n let hook = LUA_HOOKCALL;\n ci.l_savedpc++; /* hooks assume 'pc' is already incremented */\n if ((ci.previous.callstatus & lstate.CIST_LUA) &&\n ci.previous.l_code[ci.previous.l_savedpc - 1].opcode == lopcodes.OpCodesI.OP_TAILCALL) {\n ci.callstatus |= lstate.CIST_TAIL;\n hook = LUA_HOOKTAILCALL;\n }\n luaD_hook(L, hook, -1);\n ci.l_savedpc--; /* correct 'pc' */\n};\n\nconst adjust_varargs = function(L, p, actual) {\n let nfixargs = p.numparams;\n /* move fixed parameters to final position */\n let fixed = L.top - actual; /* first fixed argument */\n let base = L.top; /* final position of first argument */\n\n let i;\n for (i = 0; i < nfixargs && i < actual; i++) {\n lobject.pushobj2s(L, L.stack[fixed + i]);\n L.stack[fixed + i].setnilvalue();\n }\n\n for (; i < nfixargs; i++)\n L.stack[L.top++] = new lobject.TValue(LUA_TNIL, null);\n\n return base;\n};\n\nconst tryfuncTM = function(L, off, func) {\n let tm = ltm.luaT_gettmbyobj(L, func, ltm.TMS.TM_CALL);\n if (!tm.ttisfunction(tm))\n ldebug.luaG_typeerror(L, func, to_luastring(\"call\", true));\n /* Open a hole inside the stack at 'func' */\n lobject.pushobj2s(L, L.stack[L.top-1]); /* push top of stack again */\n for (let p = L.top-2; p > off; p--)\n lobject.setobjs2s(L, p, p-1); /* move other items up one */\n lobject.setobj2s(L, off, tm); /* tag method is the new function to be called */\n};\n\n/*\n** Check appropriate error for stack overflow (\"regular\" overflow or\n** overflow while handling stack overflow). If 'nCalls' is larger than\n** LUAI_MAXCCALLS (which means it is handling a \"regular\" overflow) but\n** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to\n** allow overflow handling to work)\n*/\nconst stackerror = function(L) {\n if (L.nCcalls === LUAI_MAXCCALLS)\n ldebug.luaG_runerror(L, to_luastring(\"JS stack overflow\", true));\n else if (L.nCcalls >= LUAI_MAXCCALLS + (LUAI_MAXCCALLS >> 3))\n luaD_throw(L, LUA_ERRERR); /* error while handing stack error */\n};\n\n/*\n** Call a function (JS or Lua). The function to be called is at func.\n** The arguments are on the stack, right after the function.\n** When returns, all the results are on the stack, starting at the original\n** function position.\n*/\nconst luaD_call = function(L, off, nResults) {\n if (++L.nCcalls >= LUAI_MAXCCALLS)\n stackerror(L);\n if (!luaD_precall(L, off, nResults))\n lvm.luaV_execute(L);\n L.nCcalls--;\n};\n\nconst luaD_throw = function(L, errcode) {\n if (L.errorJmp) { /* thread has an error handler? */\n L.errorJmp.status = errcode; /* set status */\n throw L.errorJmp;\n } else { /* thread has no error handler */\n let g = L.l_G;\n L.status = errcode; /* mark it as dead */\n if (g.mainthread.errorJmp) { /* main thread has a handler? */\n g.mainthread.stack[g.mainthread.top++] = L.stack[L.top - 1]; /* copy error obj. */\n luaD_throw(g.mainthread, errcode); /* re-throw in main thread */\n } else { /* no handler at all; abort */\n let panic = g.panic;\n if (panic) { /* panic function? */\n seterrorobj(L, errcode, L.top); /* assume EXTRA_STACK */\n if (L.ci.top < L.top)\n L.ci.top = L.top; /* pushing msg. can break this invariant */\n panic(L); /* call panic function (last chance to jump out) */\n }\n throw new Error(`Aborted ${errcode}`);\n }\n }\n};\n\nconst luaD_rawrunprotected = function(L, f, ud) {\n let oldnCcalls = L.nCcalls;\n let lj = {\n status: LUA_OK,\n previous: L.errorJmp /* chain new error handler */\n };\n L.errorJmp = lj;\n\n try {\n f(L, ud);\n } catch (e) {\n if (lj.status === LUA_OK) {\n /* error was not thrown via luaD_throw, i.e. it is a JS error */\n /* run user error handler (if it exists) */\n let atnativeerror = L.l_G.atnativeerror;\n if (atnativeerror) {\n try {\n lj.status = LUA_OK;\n\n lapi.lua_pushcfunction(L, atnativeerror);\n lapi.lua_pushlightuserdata(L, e);\n luaD_callnoyield(L, L.top - 2, 1);\n\n /* Now run the message handler (if it exists) */\n /* copy of luaG_errormsg without the throw */\n if (L.errfunc !== 0) { /* is there an error handling function? */\n let errfunc = L.errfunc;\n lobject.pushobj2s(L, L.stack[L.top - 1]); /* move argument */\n lobject.setobjs2s(L, L.top - 2, errfunc); /* push function */\n luaD_callnoyield(L, L.top - 2, 1);\n }\n\n lj.status = LUA_ERRRUN;\n } catch(e2) {\n if (lj.status === LUA_OK) {\n /* also failed */\n lj.status = -1;\n }\n }\n } else {\n lj.status = -1;\n }\n }\n }\n\n L.errorJmp = lj.previous;\n L.nCcalls = oldnCcalls;\n\n return lj.status;\n\n};\n\n/*\n** Completes the execution of an interrupted C function, calling its\n** continuation function.\n*/\nconst finishCcall = function(L, status) {\n let ci = L.ci;\n\n /* must have a continuation and must be able to call it */\n lua_assert(ci.c_k !== null && L.nny === 0);\n /* error status can only happen in a protected call */\n lua_assert(ci.callstatus & lstate.CIST_YPCALL || status === LUA_YIELD);\n\n if (ci.callstatus & lstate.CIST_YPCALL) { /* was inside a pcall? */\n ci.callstatus &= ~lstate.CIST_YPCALL; /* continuation is also inside it */\n L.errfunc = ci.c_old_errfunc; /* with the same error function */\n }\n\n /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already\n handled */\n if (ci.nresults === LUA_MULTRET && L.ci.top < L.top) L.ci.top = L.top;\n let c_k = ci.c_k; /* don't want to call as method */\n let n = c_k(L, status, ci.c_ctx); /* call continuation function */\n lapi.api_checknelems(L, n);\n luaD_poscall(L, ci, L.top - n, n); /* finish 'luaD_precall' */\n};\n\n/*\n** Executes \"full continuation\" (everything in the stack) of a\n** previously interrupted coroutine until the stack is empty (or another\n** interruption long-jumps out of the loop). If the coroutine is\n** recovering from an error, 'ud' points to the error status, which must\n** be passed to the first continuation function (otherwise the default\n** status is LUA_YIELD).\n*/\nconst unroll = function(L, ud) {\n if (ud !== null) /* error status? */\n finishCcall(L, ud); /* finish 'lua_pcallk' callee */\n\n while (L.ci !== L.base_ci) { /* something in the stack */\n if (!(L.ci.callstatus & lstate.CIST_LUA)) /* C function? */\n finishCcall(L, LUA_YIELD); /* complete its execution */\n else { /* Lua function */\n lvm.luaV_finishOp(L); /* finish interrupted instruction */\n lvm.luaV_execute(L); /* execute down to higher C 'boundary' */\n }\n }\n};\n\n/*\n** Try to find a suspended protected call (a \"recover point\") for the\n** given thread.\n*/\nconst findpcall = function(L) {\n for (let ci = L.ci; ci !== null; ci = ci.previous) { /* search for a pcall */\n if (ci.callstatus & lstate.CIST_YPCALL)\n return ci;\n }\n\n return null; /* no pending pcall */\n};\n\n/*\n** Recovers from an error in a coroutine. Finds a recover point (if\n** there is one) and completes the execution of the interrupted\n** 'luaD_pcall'. If there is no recover point, returns zero.\n*/\nconst recover = function(L, status) {\n let ci = findpcall(L);\n if (ci === null) return 0; /* no recovery point */\n /* \"finish\" luaD_pcall */\n let oldtop = ci.extra;\n lfunc.luaF_close(L, oldtop);\n seterrorobj(L, status, oldtop);\n L.ci = ci;\n L.allowhook = ci.callstatus & lstate.CIST_OAH; /* restore original 'allowhook' */\n L.nny = 0; /* should be zero to be yieldable */\n luaD_shrinkstack(L);\n L.errfunc = ci.c_old_errfunc;\n return 1; /* continue running the coroutine */\n};\n\n/*\n** Signal an error in the call to 'lua_resume', not in the execution\n** of the coroutine itself. (Such errors should not be handled by any\n** coroutine error handler and should not kill the coroutine.)\n*/\nconst resume_error = function(L, msg, narg) {\n let ts = luaS_newliteral(L, msg);\n if (narg === 0) {\n lobject.pushsvalue2s(L, ts);\n api_check(L, L.top <= L.ci.top, \"stack overflow\");\n } else {\n /* remove args from the stack */\n for (let i=1; i= LUAI_MAXCCALLS)\n return resume_error(L, \"JS stack overflow\", nargs);\n\n L.nny = 0; /* allow yields */\n\n lapi.api_checknelems(L, L.status === LUA_OK ? nargs + 1: nargs);\n\n let status = luaD_rawrunprotected(L, resume, nargs);\n if (status === -1) /* error calling 'lua_resume'? */\n status = LUA_ERRRUN;\n else { /* continue running after recoverable errors */\n while (status > LUA_YIELD && recover(L, status)) {\n /* unroll continuation */\n status = luaD_rawrunprotected(L, unroll, status);\n }\n\n if (status > LUA_YIELD) { /* unrecoverable error? */\n L.status = status; /* mark thread as 'dead' */\n seterrorobj(L, status, L.top); /* push error message */\n L.ci.top = L.top;\n } else\n lua_assert(status === L.status); /* normal end or yield */\n }\n\n L.nny = oldnny; /* restore 'nny' */\n L.nCcalls--;\n lua_assert(L.nCcalls === (from ? from.nCcalls : 0));\n return status;\n};\n\nconst lua_isyieldable = function(L) {\n return L.nny === 0;\n};\n\nconst lua_yieldk = function(L, nresults, ctx, k) {\n let ci = L.ci;\n lapi.api_checknelems(L, nresults);\n\n if (L.nny > 0) {\n if (L !== L.l_G.mainthread)\n ldebug.luaG_runerror(L, to_luastring(\"attempt to yield across a JS-call boundary\", true));\n else\n ldebug.luaG_runerror(L, to_luastring(\"attempt to yield from outside a coroutine\", true));\n }\n\n L.status = LUA_YIELD;\n ci.extra = ci.funcOff; /* save current 'func' */\n if (ci.callstatus & lstate.CIST_LUA) /* inside a hook? */\n api_check(L, k === null, \"hooks cannot continue after yielding\");\n else {\n ci.c_k = k;\n if (k !== null) /* is there a continuation? */\n ci.c_ctx = ctx; /* save context */\n ci.funcOff = L.top - nresults - 1; /* protect stack below results */\n ci.func = L.stack[ci.funcOff];\n luaD_throw(L, LUA_YIELD);\n }\n\n lua_assert(ci.callstatus & lstate.CIST_HOOKED); /* must be inside a hook */\n return 0; /* return to 'luaD_hook' */\n};\n\nconst lua_yield = function(L, n) {\n lua_yieldk(L, n, 0, null);\n};\n\nconst luaD_pcall = function(L, func, u, old_top, ef) {\n let old_ci = L.ci;\n let old_allowhooks = L.allowhook;\n let old_nny = L.nny;\n let old_errfunc = L.errfunc;\n L.errfunc = ef;\n\n let status = luaD_rawrunprotected(L, func, u);\n\n if (status !== LUA_OK) {\n lfunc.luaF_close(L, old_top);\n seterrorobj(L, status, old_top);\n L.ci = old_ci;\n L.allowhook = old_allowhooks;\n L.nny = old_nny;\n luaD_shrinkstack(L);\n }\n\n L.errfunc = old_errfunc;\n\n return status;\n};\n\n/*\n** Similar to 'luaD_call', but does not allow yields during the call\n*/\nconst luaD_callnoyield = function(L, off, nResults) {\n L.nny++;\n luaD_call(L, off, nResults);\n L.nny--;\n};\n\n/*\n** Execute a protected parser.\n*/\nclass SParser {\n constructor(z, name, mode) { /* data to 'f_parser' */\n this.z = z;\n this.buff = new MBuffer(); /* dynamic structure used by the scanner */\n this.dyd = new lparser.Dyndata(); /* dynamic structures used by the parser */\n this.mode = mode;\n this.name = name;\n }\n}\n\nconst checkmode = function(L, mode, x) {\n if (mode && luastring_indexOf(mode, x[0]) === -1) {\n lobject.luaO_pushfstring(L,\n to_luastring(\"attempt to load a %s chunk (mode is '%s')\"), x, mode);\n luaD_throw(L, LUA_ERRSYNTAX);\n }\n};\n\nconst f_parser = function(L, p) {\n let cl;\n let c = p.z.zgetc(); /* read first character */\n if (c === LUA_SIGNATURE[0]) {\n checkmode(L, p.mode, to_luastring(\"binary\", true));\n cl = lundump.luaU_undump(L, p.z, p.name);\n } else {\n checkmode(L, p.mode, to_luastring(\"text\", true));\n cl = lparser.luaY_parser(L, p.z, p.buff, p.dyd, p.name, c);\n }\n\n lua_assert(cl.nupvalues === cl.p.upvalues.length);\n lfunc.luaF_initupvals(L, cl);\n};\n\nconst luaD_protectedparser = function(L, z, name, mode) {\n let p = new SParser(z, name, mode);\n L.nny++; /* cannot yield during parsing */\n let status = luaD_pcall(L, f_parser, p, L.top, L.errfunc);\n L.nny--;\n return status;\n};\n\nmodule.exports.adjust_top = adjust_top;\nmodule.exports.luaD_call = luaD_call;\nmodule.exports.luaD_callnoyield = luaD_callnoyield;\nmodule.exports.luaD_checkstack = luaD_checkstack;\nmodule.exports.luaD_growstack = luaD_growstack;\nmodule.exports.luaD_hook = luaD_hook;\nmodule.exports.luaD_inctop = luaD_inctop;\nmodule.exports.luaD_pcall = luaD_pcall;\nmodule.exports.luaD_poscall = luaD_poscall;\nmodule.exports.luaD_precall = luaD_precall;\nmodule.exports.luaD_protectedparser = luaD_protectedparser;\nmodule.exports.luaD_rawrunprotected = luaD_rawrunprotected;\nmodule.exports.luaD_reallocstack = luaD_reallocstack;\nmodule.exports.luaD_throw = luaD_throw;\nmodule.exports.lua_isyieldable = lua_isyieldable;\nmodule.exports.lua_resume = lua_resume;\nmodule.exports.lua_yield = lua_yield;\nmodule.exports.lua_yieldk = lua_yieldk;\n","\"use strict\";\n\nconst {\n constant_types: {\n LUA_TBOOLEAN,\n LUA_TCCL,\n LUA_TLCF,\n LUA_TLCL,\n LUA_TLIGHTUSERDATA,\n LUA_TLNGSTR,\n LUA_TNIL,\n LUA_TNUMFLT,\n LUA_TNUMINT,\n LUA_TSHRSTR,\n LUA_TTABLE,\n LUA_TTHREAD,\n LUA_TUSERDATA\n },\n to_luastring\n} = require('./defs.js');\nconst { lua_assert } = require('./llimits.js');\nconst ldebug = require('./ldebug.js');\nconst lobject = require('./lobject.js');\nconst {\n luaS_hashlongstr,\n TString\n} = require('./lstring.js');\nconst lstate = require('./lstate.js');\n\n/* used to prevent conflicts with lightuserdata keys */\nlet lightuserdata_hashes = new WeakMap();\nconst get_lightuserdata_hash = function(v) {\n let hash = lightuserdata_hashes.get(v);\n if (!hash) {\n /* Hash should be something unique that is a valid WeakMap key\n so that it ends up in dead_weak when removed from a table */\n hash = {};\n lightuserdata_hashes.set(v, hash);\n }\n return hash;\n};\n\nconst table_hash = function(L, key) {\n switch(key.type) {\n case LUA_TNIL:\n return ldebug.luaG_runerror(L, to_luastring(\"table index is nil\", true));\n case LUA_TNUMFLT:\n if (isNaN(key.value))\n return ldebug.luaG_runerror(L, to_luastring(\"table index is NaN\", true));\n /* fall through */\n case LUA_TNUMINT: /* takes advantage of floats and integers being same in JS */\n case LUA_TBOOLEAN:\n case LUA_TTABLE:\n case LUA_TLCL:\n case LUA_TLCF:\n case LUA_TCCL:\n case LUA_TUSERDATA:\n case LUA_TTHREAD:\n return key.value;\n case LUA_TSHRSTR:\n case LUA_TLNGSTR:\n return luaS_hashlongstr(key.tsvalue());\n case LUA_TLIGHTUSERDATA: {\n let v = key.value;\n switch(typeof v) {\n case \"string\":\n /* possible conflict with LUA_TSTRING.\n prefix this string with \"*\" so they don't clash */\n return \"*\" + v;\n case \"number\":\n /* possible conflict with LUA_TNUMBER.\n turn into string and prefix with \"#\" to avoid clash with other strings */\n return \"#\" + v;\n case \"boolean\":\n /* possible conflict with LUA_TBOOLEAN. use strings ?true and ?false instead */\n return v?\"?true\":\"?false\";\n case \"function\":\n /* possible conflict with LUA_TLCF.\n indirect via a weakmap */\n return get_lightuserdata_hash(v);\n case \"object\":\n /* v could be a lua_State, CClosure, LClosure, Table or Userdata from this state as returned by lua_topointer */\n if ((v instanceof lstate.lua_State && v.l_G === L.l_G) ||\n v instanceof Table ||\n v instanceof lobject.Udata ||\n v instanceof lobject.LClosure ||\n v instanceof lobject.CClosure) {\n /* indirect via a weakmap */\n return get_lightuserdata_hash(v);\n }\n /* fall through */\n default:\n return v;\n }\n }\n default:\n throw new Error(\"unknown key type: \" + key.type);\n }\n};\n\nclass Table {\n constructor(L) {\n this.id = L.l_G.id_counter++;\n this.strong = new Map();\n this.dead_strong = new Map();\n this.dead_weak = void 0; /* initialised when needed */\n this.f = void 0; /* first entry */\n this.l = void 0; /* last entry */\n this.metatable = null;\n this.flags = ~0;\n }\n}\n\nconst invalidateTMcache = function(t) {\n t.flags = 0;\n};\n\nconst add = function(t, hash, key, value) {\n t.dead_strong.clear();\n t.dead_weak = void 0;\n let prev = null;\n let entry = {\n key: key,\n value: value,\n p: prev = t.l,\n n: void 0\n };\n if (!t.f) t.f = entry;\n if (prev) prev.n = entry;\n t.strong.set(hash, entry);\n t.l = entry;\n};\n\nconst is_valid_weakmap_key = function(k) {\n return typeof k === 'object' ? k !== null : typeof k === 'function';\n};\n\n/* Move out of 'strong' part and into 'dead' part. */\nconst mark_dead = function(t, hash) {\n let e = t.strong.get(hash);\n if (e) {\n e.key.setdeadvalue();\n e.value = void 0;\n let next = e.n;\n let prev = e.p;\n e.p = void 0; /* no need to know previous item any more */\n if(prev) prev.n = next;\n if(next) next.p = prev;\n if(t.f === e) t.f = next;\n if(t.l === e) t.l = prev;\n t.strong.delete(hash);\n if (is_valid_weakmap_key(hash)) {\n if (!t.dead_weak) t.dead_weak = new WeakMap();\n t.dead_weak.set(hash, e);\n } else {\n /* can't be used as key in weakmap */\n t.dead_strong.set(hash, e);\n }\n }\n};\n\nconst luaH_new = function(L) {\n return new Table(L);\n};\n\nconst getgeneric = function(t, hash) {\n let v = t.strong.get(hash);\n return v ? v.value : lobject.luaO_nilobject;\n};\n\nconst luaH_getint = function(t, key) {\n lua_assert(typeof key == \"number\" && (key|0) === key);\n return getgeneric(t, key);\n};\n\nconst luaH_getstr = function(t, key) {\n lua_assert(key instanceof TString);\n return getgeneric(t, luaS_hashlongstr(key));\n};\n\nconst luaH_get = function(L, t, key) {\n lua_assert(key instanceof lobject.TValue);\n if (key.ttisnil() || (key.ttisfloat() && isNaN(key.value)))\n return lobject.luaO_nilobject;\n return getgeneric(t, table_hash(L, key));\n};\n\nconst luaH_setint = function(t, key, value) {\n lua_assert(typeof key == \"number\" && (key|0) === key && value instanceof lobject.TValue);\n let hash = key; /* table_hash known result */\n if (value.ttisnil()) {\n mark_dead(t, hash);\n return;\n }\n let e = t.strong.get(hash);\n if (e) {\n let tv = e.value;\n tv.setfrom(value);\n } else {\n let k = new lobject.TValue(LUA_TNUMINT, key);\n let v = new lobject.TValue(value.type, value.value);\n add(t, hash, k, v);\n }\n};\n\nconst luaH_setfrom = function(L, t, key, value) {\n lua_assert(key instanceof lobject.TValue);\n let hash = table_hash(L, key);\n if (value.ttisnil()) { /* delete */\n mark_dead(t, hash);\n return;\n }\n\n let e = t.strong.get(hash);\n if (e) {\n e.value.setfrom(value);\n } else {\n let k;\n let kv = key.value;\n if ((key.ttisfloat() && (kv|0) === kv)) { /* does index fit in an integer? */\n /* insert it as an integer */\n k = new lobject.TValue(LUA_TNUMINT, kv);\n } else {\n k = new lobject.TValue(key.type, kv);\n }\n let v = new lobject.TValue(value.type, value.value);\n add(t, hash, k, v);\n }\n};\n\n/*\n** Try to find a boundary in table 't'. A 'boundary' is an integer index\n** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).\n*/\nconst luaH_getn = function(t) {\n let i = 0;\n let j = t.strong.size + 1; /* use known size of Map to bound search */\n /* now do a binary search between them */\n while (j - i > 1) {\n let m = Math.floor((i+j)/2);\n if (luaH_getint(t, m).ttisnil()) j = m;\n else i = m;\n }\n return i;\n};\n\nconst luaH_next = function(L, table, keyI) {\n let keyO = L.stack[keyI];\n\n let entry;\n if (keyO.type === LUA_TNIL) {\n entry = table.f;\n if (!entry)\n return false;\n } else {\n /* First find current key */\n let hash = table_hash(L, keyO);\n /* Look in main part of table */\n entry = table.strong.get(hash);\n if (entry) {\n entry = entry.n;\n if (!entry)\n return false;\n } else {\n /* Try dead keys */\n entry = (table.dead_weak && table.dead_weak.get(hash)) || table.dead_strong.get(hash);\n if (!entry)\n /* item not in table */\n return ldebug.luaG_runerror(L, to_luastring(\"invalid key to 'next'\"));\n /* Iterate until either out of keys, or until finding a non-dead key */\n do {\n entry = entry.n;\n if (!entry)\n return false;\n } while (entry.key.ttisdeadkey());\n }\n }\n lobject.setobj2s(L, keyI, entry.key);\n lobject.setobj2s(L, keyI+1, entry.value);\n return true;\n};\n\nmodule.exports.invalidateTMcache = invalidateTMcache;\nmodule.exports.luaH_get = luaH_get;\nmodule.exports.luaH_getint = luaH_getint;\nmodule.exports.luaH_getn = luaH_getn;\nmodule.exports.luaH_getstr = luaH_getstr;\nmodule.exports.luaH_setfrom = luaH_setfrom;\nmodule.exports.luaH_setint = luaH_setint;\nmodule.exports.luaH_new = luaH_new;\nmodule.exports.luaH_next = luaH_next;\nmodule.exports.Table = Table;\n","\"use strict\";\n\nconst {\n is_luastring,\n luastring_eq,\n luastring_from,\n to_luastring\n} = require('./defs.js');\nconst { lua_assert } = require(\"./llimits.js\");\n\nclass TString {\n\n constructor(L, str) {\n this.hash = null;\n this.realstring = str;\n }\n\n getstr() {\n return this.realstring;\n }\n\n tsslen() {\n return this.realstring.length;\n }\n\n}\n\nconst luaS_eqlngstr = function(a, b) {\n lua_assert(a instanceof TString);\n lua_assert(b instanceof TString);\n return a == b || luastring_eq(a.realstring, b.realstring);\n};\n\n/* converts strings (arrays) to a consistent map key\n make sure this doesn't conflict with any of the anti-collision strategies in ltable */\nconst luaS_hash = function(str) {\n lua_assert(is_luastring(str));\n let len = str.length;\n let s = \"|\";\n for (let i=0; i 0 && ci !== L.base_ci; ci = ci.previous)\n level--;\n if (level === 0 && ci !== L.base_ci) { /* level found? */\n status = 1;\n ar.i_ci = ci;\n } else\n status = 0; /* no such level */\n return status;\n};\n\nconst upvalname = function(p, uv) {\n lua_assert(uv < p.upvalues.length);\n let s = p.upvalues[uv].name;\n if (s === null) return to_luastring(\"?\", true);\n return s.getstr();\n};\n\nconst findvararg = function(ci, n) {\n let nparams = ci.func.value.p.numparams;\n if (n >= ci.l_base - ci.funcOff - nparams)\n return null; /* no such vararg */\n else {\n return {\n pos: ci.funcOff + nparams + n,\n name: to_luastring(\"(*vararg)\", true) /* generic name for any vararg */\n };\n }\n};\n\nconst findlocal = function(L, ci, n) {\n let base, name = null;\n\n if (ci.callstatus & lstate.CIST_LUA) {\n if (n < 0) /* access to vararg values? */\n return findvararg(ci, -n);\n else {\n base = ci.l_base;\n name = lfunc.luaF_getlocalname(ci.func.value.p, n, currentpc(ci));\n }\n } else\n base = ci.funcOff + 1;\n\n if (name === null) { /* no 'standard' name? */\n let limit = ci === L.ci ? L.top : ci.next.funcOff;\n if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */\n name = to_luastring(\"(*temporary)\", true); /* generic name for any valid slot */\n else\n return null; /* no name */\n }\n return {\n pos: base + (n - 1),\n name: name\n };\n};\n\nconst lua_getlocal = function(L, ar, n) {\n let name;\n swapextra(L);\n if (ar === null) { /* information about non-active function? */\n if (!L.stack[L.top - 1].ttisLclosure()) /* not a Lua function? */\n name = null;\n else /* consider live variables at function start (parameters) */\n name = lfunc.luaF_getlocalname(L.stack[L.top - 1].value.p, n, 0);\n } else { /* active function; get information through 'ar' */\n let local = findlocal(L, ar.i_ci, n);\n if (local) {\n name = local.name;\n lobject.pushobj2s(L, L.stack[local.pos]);\n api_check(L, L.top <= L.ci.top, \"stack overflow\");\n } else {\n name = null;\n }\n }\n swapextra(L);\n return name;\n};\n\nconst lua_setlocal = function(L, ar, n) {\n let name;\n swapextra(L);\n let local = findlocal(L, ar.i_ci, n);\n if (local) {\n name = local.name;\n lobject.setobjs2s(L, local.pos, L.top - 1);\n delete L.stack[--L.top]; /* pop value */\n } else {\n name = null;\n }\n swapextra(L);\n return name;\n};\n\nconst funcinfo = function(ar, cl) {\n if (cl === null || cl instanceof lobject.CClosure) {\n ar.source = to_luastring(\"=[JS]\", true);\n ar.linedefined = -1;\n ar.lastlinedefined = -1;\n ar.what = to_luastring(\"J\", true);\n } else {\n let p = cl.p;\n ar.source = p.source ? p.source.getstr() : to_luastring(\"=?\", true);\n ar.linedefined = p.linedefined;\n ar.lastlinedefined = p.lastlinedefined;\n ar.what = ar.linedefined === 0 ? to_luastring(\"main\", true) : to_luastring(\"Lua\", true);\n }\n\n ar.short_src = lobject.luaO_chunkid(ar.source, LUA_IDSIZE);\n};\n\nconst collectvalidlines = function(L, f) {\n if (f === null || f instanceof lobject.CClosure) {\n L.stack[L.top] = new lobject.TValue(LUA_TNIL, null);\n lapi.api_incr_top(L);\n } else {\n let lineinfo = f.p.lineinfo;\n let t = ltable.luaH_new(L);\n L.stack[L.top] = new lobject.TValue(LUA_TTABLE, t);\n lapi.api_incr_top(L);\n let v = new lobject.TValue(LUA_TBOOLEAN, true);\n for (let i = 0; i < lineinfo.length; i++)\n ltable.luaH_setint(t, lineinfo[i], v);\n }\n};\n\nconst getfuncname = function(L, ci) {\n let r = {\n name: null,\n funcname: null\n };\n if (ci === null)\n return null;\n else if (ci.callstatus & lstate.CIST_FIN) { /* is this a finalizer? */\n r.name = to_luastring(\"__gc\", true);\n r.funcname = to_luastring(\"metamethod\", true); /* report it as such */\n return r;\n }\n /* calling function is a known Lua function? */\n else if (!(ci.callstatus & lstate.CIST_TAIL) && ci.previous.callstatus & lstate.CIST_LUA)\n return funcnamefromcode(L, ci.previous);\n else return null; /* no way to find a name */\n};\n\nconst auxgetinfo = function(L, what, ar, f, ci) {\n let status = 1;\n for (; what.length > 0; what = what.subarray(1)) {\n switch (what[0]) {\n case 83 /* ('S').charCodeAt(0) */: {\n funcinfo(ar, f);\n break;\n }\n case 108 /* ('l').charCodeAt(0) */: {\n ar.currentline = ci && ci.callstatus & lstate.CIST_LUA ? currentline(ci) : -1;\n break;\n }\n case 117 /* ('u').charCodeAt(0) */: {\n ar.nups = f === null ? 0 : f.nupvalues;\n if (f === null || f instanceof lobject.CClosure) {\n ar.isvararg = true;\n ar.nparams = 0;\n } else {\n ar.isvararg = f.p.is_vararg;\n ar.nparams = f.p.numparams;\n }\n break;\n }\n case 116 /* ('t').charCodeAt(0) */: {\n ar.istailcall = ci ? ci.callstatus & lstate.CIST_TAIL : 0;\n break;\n }\n case 110 /* ('n').charCodeAt(0) */: {\n let r = getfuncname(L, ci);\n if (r === null) {\n ar.namewhat = to_luastring(\"\", true);\n ar.name = null;\n } else {\n ar.namewhat = r.funcname;\n ar.name = r.name;\n }\n break;\n }\n case 76 /* ('L').charCodeAt(0) */:\n case 102 /* ('f').charCodeAt(0) */: /* handled by lua_getinfo */\n break;\n default: status = 0; /* invalid option */\n }\n }\n\n return status;\n};\n\nconst lua_getinfo = function(L, what, ar) {\n what = from_userstring(what);\n let status, cl, ci, func;\n swapextra(L);\n if (what[0] === 62 /* ('>').charCodeAt(0) */) {\n ci = null;\n func = L.stack[L.top - 1];\n api_check(L, func.ttisfunction(), \"function expected\");\n what = what.subarray(1); /* skip the '>' */\n L.top--; /* pop function */\n } else {\n ci = ar.i_ci;\n func = ci.func;\n lua_assert(ci.func.ttisfunction());\n }\n\n cl = func.ttisclosure() ? func.value : null;\n status = auxgetinfo(L, what, ar, cl, ci);\n if (luastring_indexOf(what, 102 /* ('f').charCodeAt(0) */) >= 0) {\n lobject.pushobj2s(L, func);\n api_check(L, L.top <= L.ci.top, \"stack overflow\");\n }\n\n swapextra(L);\n if (luastring_indexOf(what, 76 /* ('L').charCodeAt(0) */) >= 0)\n collectvalidlines(L, cl);\n\n return status;\n};\n\nconst kname = function(p, pc, c) {\n let r = {\n name: null,\n funcname: null\n };\n\n if (lopcodes.ISK(c)) { /* is 'c' a constant? */\n let kvalue = p.k[lopcodes.INDEXK(c)];\n if (kvalue.ttisstring()) { /* literal constant? */\n r.name = kvalue.svalue(); /* it is its own name */\n return r;\n }\n /* else no reasonable name found */\n } else { /* 'c' is a register */\n let what = getobjname(p, pc, c); /* search for 'c' */\n if (what && what.funcname[0] === 99 /* ('c').charCodeAt(0) */) { /* found a constant name? */\n return what; /* 'name' already filled */\n }\n /* else no reasonable name found */\n }\n r.name = to_luastring(\"?\", true);\n return r; /* no reasonable name found */\n};\n\nconst filterpc = function(pc, jmptarget) {\n if (pc < jmptarget) /* is code conditional (inside a jump)? */\n return -1; /* cannot know who sets that register */\n else return pc; /* current position sets that register */\n};\n\n/*\n** try to find last instruction before 'lastpc' that modified register 'reg'\n*/\nconst findsetreg = function(p, lastpc, reg) {\n let setreg = -1; /* keep last instruction that changed 'reg' */\n let jmptarget = 0; /* any code before this address is conditional */\n let OCi = lopcodes.OpCodesI;\n for (let pc = 0; pc < lastpc; pc++) {\n let i = p.code[pc];\n let a = i.A;\n switch (i.opcode) {\n case OCi.OP_LOADNIL: {\n let b = i.B;\n if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */\n setreg = filterpc(pc, jmptarget);\n break;\n }\n case OCi.OP_TFORCALL: {\n if (reg >= a + 2) /* affect all regs above its base */\n setreg = filterpc(pc, jmptarget);\n break;\n }\n case OCi.OP_CALL:\n case OCi.OP_TAILCALL: {\n if (reg >= a) /* affect all registers above base */\n setreg = filterpc(pc, jmptarget);\n break;\n }\n case OCi.OP_JMP: {\n let b = i.sBx;\n let dest = pc + 1 + b;\n /* jump is forward and do not skip 'lastpc'? */\n if (pc < dest && dest <= lastpc) {\n if (dest > jmptarget)\n jmptarget = dest; /* update 'jmptarget' */\n }\n break;\n }\n default:\n if (lopcodes.testAMode(i.opcode) && reg === a)\n setreg = filterpc(pc, jmptarget);\n break;\n }\n }\n\n return setreg;\n};\n\n\nconst getobjname = function(p, lastpc, reg) {\n let r = {\n name: lfunc.luaF_getlocalname(p, reg + 1, lastpc),\n funcname: null\n };\n\n if (r.name) { /* is a local? */\n r.funcname = to_luastring(\"local\", true);\n return r;\n }\n\n /* else try symbolic execution */\n let pc = findsetreg(p, lastpc, reg);\n let OCi = lopcodes.OpCodesI;\n if (pc !== -1) { /* could find instruction? */\n let i = p.code[pc];\n switch (i.opcode) {\n case OCi.OP_MOVE: {\n let b = i.B; /* move from 'b' to 'a' */\n if (b < i.A)\n return getobjname(p, pc, b); /* get name for 'b' */\n break;\n }\n case OCi.OP_GETTABUP:\n case OCi.OP_GETTABLE: {\n let k = i.C; /* key index */\n let t = i.B; /* table index */\n let vn = i.opcode === OCi.OP_GETTABLE ? lfunc.luaF_getlocalname(p, t + 1, pc) : upvalname(p, t);\n r.name = kname(p, pc, k).name;\n r.funcname = (vn && luastring_eq(vn, llex.LUA_ENV)) ? to_luastring(\"global\", true) : to_luastring(\"field\", true);\n return r;\n }\n case OCi.OP_GETUPVAL: {\n r.name = upvalname(p, i.B);\n r.funcname = to_luastring(\"upvalue\", true);\n return r;\n }\n case OCi.OP_LOADK:\n case OCi.OP_LOADKX: {\n let b = i.opcode === OCi.OP_LOADK ? i.Bx : p.code[pc + 1].Ax;\n if (p.k[b].ttisstring()) {\n r.name = p.k[b].svalue();\n r.funcname = to_luastring(\"constant\", true);\n return r;\n }\n break;\n }\n case OCi.OP_SELF: {\n let k = i.C;\n r.name = kname(p, pc, k).name;\n r.funcname = to_luastring(\"method\", true);\n return r;\n }\n default: break;\n }\n }\n\n return null;\n};\n\n/*\n** Try to find a name for a function based on the code that called it.\n** (Only works when function was called by a Lua function.)\n** Returns what the name is (e.g., \"for iterator\", \"method\",\n** \"metamethod\") and sets '*name' to point to the name.\n*/\nconst funcnamefromcode = function(L, ci) {\n let r = {\n name: null,\n funcname: null\n };\n\n let tm = 0; /* (initial value avoids warnings) */\n let p = ci.func.value.p; /* calling function */\n let pc = currentpc(ci); /* calling instruction index */\n let i = p.code[pc]; /* calling instruction */\n let OCi = lopcodes.OpCodesI;\n\n if (ci.callstatus & lstate.CIST_HOOKED) {\n r.name = to_luastring(\"?\", true);\n r.funcname = to_luastring(\"hook\", true);\n return r;\n }\n\n switch (i.opcode) {\n case OCi.OP_CALL:\n case OCi.OP_TAILCALL:\n return getobjname(p, pc, i.A); /* get function name */\n case OCi.OP_TFORCALL:\n r.name = to_luastring(\"for iterator\", true);\n r.funcname = to_luastring(\"for iterator\", true);\n return r;\n /* other instructions can do calls through metamethods */\n case OCi.OP_SELF:\n case OCi.OP_GETTABUP:\n case OCi.OP_GETTABLE:\n tm = ltm.TMS.TM_INDEX;\n break;\n case OCi.OP_SETTABUP:\n case OCi.OP_SETTABLE:\n tm = ltm.TMS.TM_NEWINDEX;\n break;\n case OCi.OP_ADD: tm = ltm.TMS.TM_ADD; break;\n case OCi.OP_SUB: tm = ltm.TMS.TM_SUB; break;\n case OCi.OP_MUL: tm = ltm.TMS.TM_MUL; break;\n case OCi.OP_MOD: tm = ltm.TMS.TM_MOD; break;\n case OCi.OP_POW: tm = ltm.TMS.TM_POW; break;\n case OCi.OP_DIV: tm = ltm.TMS.TM_DIV; break;\n case OCi.OP_IDIV: tm = ltm.TMS.TM_IDIV; break;\n case OCi.OP_BAND: tm = ltm.TMS.TM_BAND; break;\n case OCi.OP_BOR: tm = ltm.TMS.TM_BOR; break;\n case OCi.OP_BXOR: tm = ltm.TMS.TM_BXOR; break;\n case OCi.OP_SHL: tm = ltm.TMS.TM_SHL; break;\n case OCi.OP_SHR: tm = ltm.TMS.TM_SHR; break;\n case OCi.OP_UNM: tm = ltm.TMS.TM_UNM; break;\n case OCi.OP_BNOT: tm = ltm.TMS.TM_BNOT; break;\n case OCi.OP_LEN: tm = ltm.TMS.TM_LEN; break;\n case OCi.OP_CONCAT: tm = ltm.TMS.TM_CONCAT; break;\n case OCi.OP_EQ: tm = ltm.TMS.TM_EQ; break;\n case OCi.OP_LT: tm = ltm.TMS.TM_LT; break;\n case OCi.OP_LE: tm = ltm.TMS.TM_LE; break;\n default:\n return null; /* cannot find a reasonable name */\n }\n\n r.name = L.l_G.tmname[tm].getstr();\n r.funcname = to_luastring(\"metamethod\", true);\n return r;\n};\n\nconst isinstack = function(L, ci, o) {\n for (let i = ci.l_base; i < ci.top; i++) {\n if (L.stack[i] === o)\n return i;\n }\n\n return false;\n};\n\n/*\n** Checks whether value 'o' came from an upvalue. (That can only happen\n** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on\n** upvalues.)\n*/\nconst getupvalname = function(L, ci, o) {\n let c = ci.func.value;\n for (let i = 0; i < c.nupvalues; i++) {\n if (c.upvals[i] === o) {\n return {\n name: upvalname(c.p, i),\n funcname: to_luastring('upvalue', true)\n };\n }\n }\n\n return null;\n};\n\nconst varinfo = function(L, o) {\n let ci = L.ci;\n let kind = null;\n if (ci.callstatus & lstate.CIST_LUA) {\n kind = getupvalname(L, ci, o); /* check whether 'o' is an upvalue */\n let stkid = isinstack(L, ci, o);\n if (!kind && stkid) /* no? try a register */\n kind = getobjname(ci.func.value.p, currentpc(ci), stkid - ci.l_base);\n }\n\n return kind ? lobject.luaO_pushfstring(L, to_luastring(\" (%s '%s')\", true), kind.funcname, kind.name) : to_luastring(\"\", true);\n};\n\nconst luaG_typeerror = function(L, o, op) {\n let t = ltm.luaT_objtypename(L, o);\n luaG_runerror(L, to_luastring(\"attempt to %s a %s value%s\", true), op, t, varinfo(L, o));\n};\n\nconst luaG_concaterror = function(L, p1, p2) {\n if (p1.ttisstring() || lvm.cvt2str(p1)) p1 = p2;\n luaG_typeerror(L, p1, to_luastring('concatenate', true));\n};\n\n/*\n** Error when both values are convertible to numbers, but not to integers\n*/\nconst luaG_opinterror = function(L, p1, p2, msg) {\n if (lvm.tonumber(p1) === false)\n p2 = p1;\n luaG_typeerror(L, p2, msg);\n};\n\nconst luaG_ordererror = function(L, p1, p2) {\n let t1 = ltm.luaT_objtypename(L, p1);\n let t2 = ltm.luaT_objtypename(L, p2);\n if (luastring_eq(t1, t2))\n luaG_runerror(L, to_luastring(\"attempt to compare two %s values\", true), t1);\n else\n luaG_runerror(L, to_luastring(\"attempt to compare %s with %s\", true), t1, t2);\n};\n\n/* add src:line information to 'msg' */\nconst luaG_addinfo = function(L, msg, src, line) {\n let buff;\n if (src)\n buff = lobject.luaO_chunkid(src.getstr(), LUA_IDSIZE);\n else\n buff = to_luastring(\"?\", true);\n\n return lobject.luaO_pushfstring(L, to_luastring(\"%s:%d: %s\", true), buff, line, msg);\n};\n\nconst luaG_runerror = function(L, fmt, ...argp) {\n let ci = L.ci;\n let msg = lobject.luaO_pushvfstring(L, fmt, argp);\n if (ci.callstatus & lstate.CIST_LUA) /* if Lua function, add source:line information */\n luaG_addinfo(L, msg, ci.func.value.p.source, currentline(ci));\n luaG_errormsg(L);\n};\n\nconst luaG_errormsg = function(L) {\n if (L.errfunc !== 0) { /* is there an error handling function? */\n let errfunc = L.errfunc;\n lobject.pushobj2s(L, L.stack[L.top - 1]); /* move argument */\n lobject.setobjs2s(L, L.top - 2, errfunc); /* push function */\n ldo.luaD_callnoyield(L, L.top - 2, 1);\n }\n\n ldo.luaD_throw(L, LUA_ERRRUN);\n};\n\n/*\n** Error when both values are convertible to numbers, but not to integers\n*/\nconst luaG_tointerror = function(L, p1, p2) {\n let temp = lvm.tointeger(p1);\n if (temp === false)\n p2 = p1;\n luaG_runerror(L, to_luastring(\"number%s has no integer representation\", true), varinfo(L, p2));\n};\n\nconst luaG_traceexec = function(L) {\n let ci = L.ci;\n let mask = L.hookmask;\n let counthook = (--L.hookcount === 0 && (mask & LUA_MASKCOUNT));\n if (counthook)\n L.hookcount = L.basehookcount; /* reset count */\n else if (!(mask & LUA_MASKLINE))\n return; /* no line hook and count != 0; nothing to be done */\n if (ci.callstatus & lstate.CIST_HOOKYIELD) { /* called hook last time? */\n ci.callstatus &= ~lstate.CIST_HOOKYIELD; /* erase mark */\n return; /* do not call hook again (VM yielded, so it did not move) */\n }\n if (counthook)\n ldo.luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */\n if (mask & LUA_MASKLINE) {\n let p = ci.func.value.p;\n let npc = ci.l_savedpc - 1; // pcRel(ci.u.l.savedpc, p);\n let newline = p.lineinfo.length !== 0 ? p.lineinfo[npc] : -1;\n if (npc === 0 || /* call linehook when enter a new function, */\n ci.l_savedpc <= L.oldpc || /* when jump back (loop), or when */\n newline !== (p.lineinfo.length !== 0 ? p.lineinfo[L.oldpc - 1] : -1)) /* enter a new line */\n ldo.luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */\n }\n L.oldpc = ci.l_savedpc;\n if (L.status === LUA_YIELD) { /* did hook yield? */\n if (counthook)\n L.hookcount = 1; /* undo decrement to zero */\n ci.l_savedpc--; /* undo increment (resume will increment it again) */\n ci.callstatus |= lstate.CIST_HOOKYIELD; /* mark that it yielded */\n ci.funcOff = L.top - 1; /* protect stack below results */\n ci.func = L.stack[ci.funcOff];\n ldo.luaD_throw(L, LUA_YIELD);\n }\n};\n\nmodule.exports.luaG_addinfo = luaG_addinfo;\nmodule.exports.luaG_concaterror = luaG_concaterror;\nmodule.exports.luaG_errormsg = luaG_errormsg;\nmodule.exports.luaG_opinterror = luaG_opinterror;\nmodule.exports.luaG_ordererror = luaG_ordererror;\nmodule.exports.luaG_runerror = luaG_runerror;\nmodule.exports.luaG_tointerror = luaG_tointerror;\nmodule.exports.luaG_traceexec = luaG_traceexec;\nmodule.exports.luaG_typeerror = luaG_typeerror;\nmodule.exports.lua_gethook = lua_gethook;\nmodule.exports.lua_gethookcount = lua_gethookcount;\nmodule.exports.lua_gethookmask = lua_gethookmask;\nmodule.exports.lua_getinfo = lua_getinfo;\nmodule.exports.lua_getlocal = lua_getlocal;\nmodule.exports.lua_getstack = lua_getstack;\nmodule.exports.lua_sethook = lua_sethook;\nmodule.exports.lua_setlocal = lua_setlocal;\n","\"use strict\";\n\nconst {\n LUA_MINSTACK,\n LUA_RIDX_GLOBALS,\n LUA_RIDX_MAINTHREAD,\n constant_types: {\n LUA_NUMTAGS,\n LUA_TNIL,\n LUA_TTABLE,\n LUA_TTHREAD\n },\n thread_status: {\n LUA_OK\n }\n} = require('./defs.js');\nconst lobject = require('./lobject.js');\nconst ldo = require('./ldo.js');\nconst lapi = require('./lapi.js');\nconst ltable = require('./ltable.js');\nconst ltm = require('./ltm.js');\n\nconst EXTRA_STACK = 5;\n\nconst BASIC_STACK_SIZE = 2 * LUA_MINSTACK;\n\nclass CallInfo {\n\n constructor() {\n this.func = null;\n this.funcOff = NaN;\n this.top = NaN;\n this.previous = null;\n this.next = null;\n\n /* only for Lua functions */\n this.l_base = NaN; /* base for this function */\n this.l_code = null; /* reference to this.func.p.code */\n this.l_savedpc = NaN; /* offset into l_code */\n /* only for JS functions */\n this.c_k = null; /* continuation in case of yields */\n this.c_old_errfunc = null;\n this.c_ctx = null; /* context info. in case of yields */\n\n this.nresults = NaN;\n this.callstatus = NaN;\n }\n\n}\n\nclass lua_State {\n\n constructor(g) {\n this.id = g.id_counter++;\n\n this.base_ci = new CallInfo(); /* CallInfo for first level (C calling Lua) */\n this.top = NaN; /* first free slot in the stack */\n this.stack_last = NaN; /* last free slot in the stack */\n this.oldpc = NaN; /* last pc traced */\n\n /* preinit_thread */\n this.l_G = g;\n this.stack = null;\n this.ci = null;\n this.errorJmp = null;\n this.nCcalls = 0;\n this.hook = null;\n this.hookmask = 0;\n this.basehookcount = 0;\n this.allowhook = 1;\n this.hookcount = this.basehookcount;\n this.nny = 1;\n this.status = LUA_OK;\n this.errfunc = 0;\n }\n\n}\n\nclass global_State {\n\n constructor() {\n this.id_counter = 1; /* used to give objects unique ids */\n this.ids = new WeakMap();\n\n this.mainthread = null;\n this.l_registry = new lobject.TValue(LUA_TNIL, null);\n this.panic = null;\n this.atnativeerror = null;\n this.version = null;\n this.tmname = new Array(ltm.TMS.TM_N);\n this.mt = new Array(LUA_NUMTAGS);\n }\n\n}\n\nconst luaE_extendCI = function(L) {\n let ci = new CallInfo();\n L.ci.next = ci;\n ci.previous = L.ci;\n ci.next = null;\n L.ci = ci;\n return ci;\n};\n\nconst luaE_freeCI = function(L) {\n let ci = L.ci;\n ci.next = null;\n};\n\nconst stack_init = function(L1, L) {\n L1.stack = new Array(BASIC_STACK_SIZE);\n L1.top = 0;\n L1.stack_last = BASIC_STACK_SIZE - EXTRA_STACK;\n /* initialize first ci */\n let ci = L1.base_ci;\n ci.next = ci.previous = null;\n ci.callstatus = 0;\n ci.funcOff = L1.top;\n ci.func = L1.stack[L1.top];\n L1.stack[L1.top++] = new lobject.TValue(LUA_TNIL, null);\n ci.top = L1.top + LUA_MINSTACK;\n L1.ci = ci;\n};\n\nconst freestack = function(L) {\n L.ci = L.base_ci;\n luaE_freeCI(L);\n L.stack = null;\n};\n\n/*\n** Create registry table and its predefined values\n*/\nconst init_registry = function(L, g) {\n let registry = ltable.luaH_new(L);\n g.l_registry.sethvalue(registry);\n ltable.luaH_setint(registry, LUA_RIDX_MAINTHREAD, new lobject.TValue(LUA_TTHREAD, L));\n ltable.luaH_setint(registry, LUA_RIDX_GLOBALS, new lobject.TValue(LUA_TTABLE, ltable.luaH_new(L)));\n};\n\n/*\n** open parts of the state that may cause memory-allocation errors.\n** ('g->version' !== NULL flags that the state was completely build)\n*/\nconst f_luaopen = function(L) {\n let g = L.l_G;\n stack_init(L, L);\n init_registry(L, g);\n ltm.luaT_init(L);\n g.version = lapi.lua_version(null);\n};\n\nconst lua_newthread = function(L) {\n let g = L.l_G;\n let L1 = new lua_State(g);\n L.stack[L.top] = new lobject.TValue(LUA_TTHREAD, L1);\n lapi.api_incr_top(L);\n L1.hookmask = L.hookmask;\n L1.basehookcount = L.basehookcount;\n L1.hook = L.hook;\n L1.hookcount = L1.basehookcount;\n stack_init(L1, L);\n return L1;\n};\n\nconst luaE_freethread = function(L, L1) {\n freestack(L1);\n};\n\nconst lua_newstate = function() {\n let g = new global_State();\n let L = new lua_State(g);\n g.mainthread = L;\n\n if (ldo.luaD_rawrunprotected(L, f_luaopen, null) !== LUA_OK) {\n L = null;\n }\n\n return L;\n};\n\nconst close_state = function(L) {\n freestack(L);\n};\n\nconst lua_close = function(L) {\n L = L.l_G.mainthread; /* only the main thread can be closed */\n close_state(L);\n};\n\nmodule.exports.lua_State = lua_State;\nmodule.exports.CallInfo = CallInfo;\nmodule.exports.CIST_OAH = (1<<0); /* original value of 'allowhook' */\nmodule.exports.CIST_LUA = (1<<1); /* call is running a Lua function */\nmodule.exports.CIST_HOOKED = (1<<2); /* call is running a debug hook */\nmodule.exports.CIST_FRESH = (1<<3); /* call is running on a fresh invocation of luaV_execute */\nmodule.exports.CIST_YPCALL = (1<<4); /* call is a yieldable protected call */\nmodule.exports.CIST_TAIL = (1<<5); /* call was tail called */\nmodule.exports.CIST_HOOKYIELD = (1<<6); /* last hook called yielded */\nmodule.exports.CIST_LEQ = (1<<7); /* using __lt for __le */\nmodule.exports.CIST_FIN = (1<<8); /* call is running a finalizer */\nmodule.exports.EXTRA_STACK = EXTRA_STACK;\nmodule.exports.lua_close = lua_close;\nmodule.exports.lua_newstate = lua_newstate;\nmodule.exports.lua_newthread = lua_newthread;\nmodule.exports.luaE_extendCI = luaE_extendCI;\nmodule.exports.luaE_freeCI = luaE_freeCI;\nmodule.exports.luaE_freethread = luaE_freethread;\n","\"use strict\";\n\nconst { constant_types: { LUA_TNIL } } = require('./defs.js');\nconst lobject = require('./lobject.js');\n\nclass Proto {\n constructor(L) {\n this.id = L.l_G.id_counter++;\n this.k = []; // constants used by the function\n this.p = []; // functions defined inside the function\n this.code = []; // opcodes\n this.cache = null; // last-created closure with this prototype\n this.lineinfo = []; // map from opcodes to source lines (debug information)\n this.upvalues = []; // upvalue information\n this.numparams = 0; // number of fixed parameters\n this.is_vararg = false;\n this.maxstacksize = 0; // number of registers needed by this function\n this.locvars = []; // information about local variables (debug information)\n this.linedefined = 0; // debug information\n this.lastlinedefined = 0; // debug information\n this.source = null; // used for debug information\n }\n}\n\nconst luaF_newLclosure = function(L, n) {\n return new lobject.LClosure(L, n);\n};\n\n\nconst luaF_findupval = function(L, level) {\n return L.stack[level];\n};\n\nconst luaF_close = function(L, level) {\n /* Create new TValues on stack;\n * any closures will keep referencing old TValues */\n for (let i=level; i to_luastring(e));\n\nconst ttypename = function(t) {\n return luaT_typenames_[t + 1];\n};\n\n\n/*\n* WARNING: if you change the order of this enumeration,\n* grep \"ORDER TM\" and \"ORDER OP\"\n*/\nconst TMS = {\n TM_INDEX: 0,\n TM_NEWINDEX: 1,\n TM_GC: 2,\n TM_MODE: 3,\n TM_LEN: 4,\n TM_EQ: 5, /* last tag method with fast access */\n TM_ADD: 6,\n TM_SUB: 7,\n TM_MUL: 8,\n TM_MOD: 9,\n TM_POW: 10,\n TM_DIV: 11,\n TM_IDIV: 12,\n TM_BAND: 13 ,\n TM_BOR: 14,\n TM_BXOR: 15,\n TM_SHL: 16,\n TM_SHR: 17,\n TM_UNM: 18,\n TM_BNOT: 19,\n TM_LT: 20,\n TM_LE: 21,\n TM_CONCAT: 22,\n TM_CALL: 23,\n TM_N: 24 /* number of elements in the enum */\n};\n\nconst luaT_init = function(L) {\n L.l_G.tmname[TMS.TM_INDEX] = new luaS_new(L, to_luastring(\"__index\", true));\n L.l_G.tmname[TMS.TM_NEWINDEX] = new luaS_new(L, to_luastring(\"__newindex\", true));\n L.l_G.tmname[TMS.TM_GC] = new luaS_new(L, to_luastring(\"__gc\", true));\n L.l_G.tmname[TMS.TM_MODE] = new luaS_new(L, to_luastring(\"__mode\", true));\n L.l_G.tmname[TMS.TM_LEN] = new luaS_new(L, to_luastring(\"__len\", true));\n L.l_G.tmname[TMS.TM_EQ] = new luaS_new(L, to_luastring(\"__eq\", true));\n L.l_G.tmname[TMS.TM_ADD] = new luaS_new(L, to_luastring(\"__add\", true));\n L.l_G.tmname[TMS.TM_SUB] = new luaS_new(L, to_luastring(\"__sub\", true));\n L.l_G.tmname[TMS.TM_MUL] = new luaS_new(L, to_luastring(\"__mul\", true));\n L.l_G.tmname[TMS.TM_MOD] = new luaS_new(L, to_luastring(\"__mod\", true));\n L.l_G.tmname[TMS.TM_POW] = new luaS_new(L, to_luastring(\"__pow\", true));\n L.l_G.tmname[TMS.TM_DIV] = new luaS_new(L, to_luastring(\"__div\", true));\n L.l_G.tmname[TMS.TM_IDIV] = new luaS_new(L, to_luastring(\"__idiv\", true));\n L.l_G.tmname[TMS.TM_BAND] = new luaS_new(L, to_luastring(\"__band\", true));\n L.l_G.tmname[TMS.TM_BOR] = new luaS_new(L, to_luastring(\"__bor\", true));\n L.l_G.tmname[TMS.TM_BXOR] = new luaS_new(L, to_luastring(\"__bxor\", true));\n L.l_G.tmname[TMS.TM_SHL] = new luaS_new(L, to_luastring(\"__shl\", true));\n L.l_G.tmname[TMS.TM_SHR] = new luaS_new(L, to_luastring(\"__shr\", true));\n L.l_G.tmname[TMS.TM_UNM] = new luaS_new(L, to_luastring(\"__unm\", true));\n L.l_G.tmname[TMS.TM_BNOT] = new luaS_new(L, to_luastring(\"__bnot\", true));\n L.l_G.tmname[TMS.TM_LT] = new luaS_new(L, to_luastring(\"__lt\", true));\n L.l_G.tmname[TMS.TM_LE] = new luaS_new(L, to_luastring(\"__le\", true));\n L.l_G.tmname[TMS.TM_CONCAT] = new luaS_new(L, to_luastring(\"__concat\", true));\n L.l_G.tmname[TMS.TM_CALL] = new luaS_new(L, to_luastring(\"__call\", true));\n};\n\n/*\n** Return the name of the type of an object. For tables and userdata\n** with metatable, use their '__name' metafield, if present.\n*/\nconst __name = to_luastring('__name', true);\nconst luaT_objtypename = function(L, o) {\n let mt;\n if ((o.ttistable() && (mt = o.value.metatable) !== null) ||\n (o.ttisfulluserdata() && (mt = o.value.metatable) !== null)) {\n let name = ltable.luaH_getstr(mt, luaS_bless(L, __name));\n if (name.ttisstring())\n return name.svalue();\n }\n return ttypename(o.ttnov());\n};\n\nconst luaT_callTM = function(L, f, p1, p2, p3, hasres) {\n let func = L.top;\n\n lobject.pushobj2s(L, f); /* push function (assume EXTRA_STACK) */\n lobject.pushobj2s(L, p1); /* 1st argument */\n lobject.pushobj2s(L, p2); /* 2nd argument */\n\n if (!hasres) /* no result? 'p3' is third argument */\n lobject.pushobj2s(L, p3); /* 3rd argument */\n\n if (L.ci.callstatus & lstate.CIST_LUA)\n ldo.luaD_call(L, func, hasres);\n else\n ldo.luaD_callnoyield(L, func, hasres);\n\n if (hasres) { /* if has result, move it to its place */\n let tv = L.stack[L.top-1];\n delete L.stack[--L.top];\n p3.setfrom(tv);\n }\n};\n\nconst luaT_callbinTM = function(L, p1, p2, res, event) {\n let tm = luaT_gettmbyobj(L, p1, event);\n if (tm.ttisnil())\n tm = luaT_gettmbyobj(L, p2, event);\n if (tm.ttisnil()) return false;\n luaT_callTM(L, tm, p1, p2, res, 1);\n return true;\n};\n\nconst luaT_trybinTM = function(L, p1, p2, res, event) {\n if (!luaT_callbinTM(L, p1, p2, res, event)) {\n switch (event) {\n case TMS.TM_CONCAT:\n return ldebug.luaG_concaterror(L, p1, p2);\n case TMS.TM_BAND: case TMS.TM_BOR: case TMS.TM_BXOR:\n case TMS.TM_SHL: case TMS.TM_SHR: case TMS.TM_BNOT: {\n let n1 = lvm.tonumber(p1);\n let n2 = lvm.tonumber(p2);\n if (n1 !== false && n2 !== false)\n return ldebug.luaG_tointerror(L, p1, p2);\n else\n return ldebug.luaG_opinterror(L, p1, p2, to_luastring(\"perform bitwise operation on\", true));\n }\n default:\n return ldebug.luaG_opinterror(L, p1, p2, to_luastring(\"perform arithmetic on\", true));\n }\n }\n};\n\nconst luaT_callorderTM = function(L, p1, p2, event) {\n let res = new lobject.TValue();\n if (!luaT_callbinTM(L, p1, p2, res, event))\n return null;\n else\n return !res.l_isfalse();\n};\n\nconst fasttm = function(l, et, e) {\n return et === null ? null :\n (et.flags & (1 << e)) ? null : luaT_gettm(et, e, l.l_G.tmname[e]);\n};\n\nconst luaT_gettm = function(events, event, ename) {\n const tm = ltable.luaH_getstr(events, ename);\n lua_assert(event <= TMS.TM_EQ);\n if (tm.ttisnil()) { /* no tag method? */\n events.flags |= 1< 1) { /* are there elements to concat? */\n L.top = top - 1; /* top is one after last element (at top-2) */\n luaV_concat(L, total); /* concat them (may yield again) */\n }\n /* move final result to final position */\n lobject.setobjs2s(L, ci.l_base + inst.A, L.top - 1);\n ldo.adjust_top(L, ci.top); /* restore top */\n break;\n }\n case OP_TFORCALL: {\n lua_assert(ci.l_code[ci.l_savedpc].opcode === OP_TFORLOOP);\n ldo.adjust_top(L, ci.top); /* correct top */\n break;\n }\n case OP_CALL: {\n if (inst.C - 1 >= 0) /* nresults >= 0? */\n ldo.adjust_top(L, ci.top); /* adjust results */\n break;\n }\n }\n};\n\nconst RA = function(L, base, i) {\n return base + i.A;\n};\n\nconst RB = function(L, base, i) {\n return base + i.B;\n};\n\n// const RC = function(L, base, i) {\n// return base + i.C;\n// };\n\nconst RKB = function(L, base, k, i) {\n return ISK(i.B) ? k[INDEXK(i.B)] : L.stack[base + i.B];\n};\n\nconst RKC = function(L, base, k, i) {\n return ISK(i.C) ? k[INDEXK(i.C)] : L.stack[base + i.C];\n};\n\nconst luaV_execute = function(L) {\n let ci = L.ci;\n\n ci.callstatus |= lstate.CIST_FRESH;\n newframe:\n for (;;) {\n lua_assert(ci === L.ci);\n let cl = ci.func.value;\n let k = cl.p.k;\n let base = ci.l_base;\n\n let i = ci.l_code[ci.l_savedpc++];\n\n if (L.hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) {\n ldebug.luaG_traceexec(L);\n }\n\n let ra = RA(L, base, i);\n let opcode = i.opcode;\n\n switch (opcode) {\n case OP_MOVE: {\n lobject.setobjs2s(L, ra, RB(L, base, i));\n break;\n }\n case OP_LOADK: {\n let konst = k[i.Bx];\n lobject.setobj2s(L, ra, konst);\n break;\n }\n case OP_LOADKX: {\n lua_assert(ci.l_code[ci.l_savedpc].opcode === OP_EXTRAARG);\n let konst = k[ci.l_code[ci.l_savedpc++].Ax];\n lobject.setobj2s(L, ra, konst);\n break;\n }\n case OP_LOADBOOL: {\n L.stack[ra].setbvalue(i.B !== 0);\n\n if (i.C !== 0)\n ci.l_savedpc++; /* skip next instruction (if C) */\n\n break;\n }\n case OP_LOADNIL: {\n for (let j = 0; j <= i.B; j++)\n L.stack[ra + j].setnilvalue();\n break;\n }\n case OP_GETUPVAL: {\n let b = i.B;\n lobject.setobj2s(L, ra, cl.upvals[b]);\n break;\n }\n case OP_GETTABUP: {\n let upval = cl.upvals[i.B];\n let rc = RKC(L, base, k, i);\n luaV_gettable(L, upval, rc, ra);\n break;\n }\n case OP_GETTABLE: {\n let rb = L.stack[RB(L, base, i)];\n let rc = RKC(L, base, k, i);\n luaV_gettable(L, rb, rc, ra);\n break;\n }\n case OP_SETTABUP: {\n let upval = cl.upvals[i.A];\n let rb = RKB(L, base, k, i);\n let rc = RKC(L, base, k, i);\n settable(L, upval, rb, rc);\n break;\n }\n case OP_SETUPVAL: {\n let uv = cl.upvals[i.B];\n uv.setfrom(L.stack[ra]);\n break;\n }\n case OP_SETTABLE: {\n let table = L.stack[ra];\n let key = RKB(L, base, k, i);\n let v = RKC(L, base, k, i);\n\n settable(L, table, key, v);\n break;\n }\n case OP_NEWTABLE: {\n L.stack[ra].sethvalue(ltable.luaH_new(L));\n break;\n }\n case OP_SELF: {\n let rb = RB(L, base, i);\n let rc = RKC(L, base, k, i);\n lobject.setobjs2s(L, ra + 1, rb);\n luaV_gettable(L, L.stack[rb], rc, ra);\n break;\n }\n case OP_ADD: {\n let op1 = RKB(L, base, k, i);\n let op2 = RKC(L, base, k, i);\n let numberop1, numberop2;\n\n if (op1.ttisinteger() && op2.ttisinteger()) {\n L.stack[ra].setivalue((op1.value + op2.value)|0);\n } else if ((numberop1 = tonumber(op1)) !== false && (numberop2 = tonumber(op2)) !== false) {\n L.stack[ra].setfltvalue(numberop1 + numberop2);\n } else {\n ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_ADD);\n }\n break;\n }\n case OP_SUB: {\n let op1 = RKB(L, base, k, i);\n let op2 = RKC(L, base, k, i);\n let numberop1, numberop2;\n\n if (op1.ttisinteger() && op2.ttisinteger()) {\n L.stack[ra].setivalue((op1.value - op2.value)|0);\n } else if ((numberop1 = tonumber(op1)) !== false && (numberop2 = tonumber(op2)) !== false) {\n L.stack[ra].setfltvalue(numberop1 - numberop2);\n } else {\n ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_SUB);\n }\n break;\n }\n case OP_MUL: {\n let op1 = RKB(L, base, k, i);\n let op2 = RKC(L, base, k, i);\n let numberop1, numberop2;\n\n if (op1.ttisinteger() && op2.ttisinteger()) {\n L.stack[ra].setivalue(luaV_imul(op1.value, op2.value));\n } else if ((numberop1 = tonumber(op1)) !== false && (numberop2 = tonumber(op2)) !== false) {\n L.stack[ra].setfltvalue(numberop1 * numberop2);\n } else {\n ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_MUL);\n }\n break;\n }\n case OP_MOD: {\n let op1 = RKB(L, base, k, i);\n let op2 = RKC(L, base, k, i);\n let numberop1, numberop2;\n\n if (op1.ttisinteger() && op2.ttisinteger()) {\n L.stack[ra].setivalue(luaV_mod(L, op1.value, op2.value));\n } else if ((numberop1 = tonumber(op1)) !== false && (numberop2 = tonumber(op2)) !== false) {\n L.stack[ra].setfltvalue(luai_nummod(L, numberop1, numberop2));\n } else {\n ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_MOD);\n }\n break;\n }\n case OP_POW: {\n let op1 = RKB(L, base, k, i);\n let op2 = RKC(L, base, k, i);\n let numberop1, numberop2;\n\n if ((numberop1 = tonumber(op1)) !== false && (numberop2 = tonumber(op2)) !== false) {\n L.stack[ra].setfltvalue(Math.pow(numberop1, numberop2));\n } else {\n ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_POW);\n }\n break;\n }\n case OP_DIV: {\n let op1 = RKB(L, base, k, i);\n let op2 = RKC(L, base, k, i);\n let numberop1, numberop2;\n\n if ((numberop1 = tonumber(op1)) !== false && (numberop2 = tonumber(op2)) !== false) {\n L.stack[ra].setfltvalue(numberop1 / numberop2);\n } else {\n ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_DIV);\n }\n break;\n }\n case OP_IDIV: {\n let op1 = RKB(L, base, k, i);\n let op2 = RKC(L, base, k, i);\n let numberop1, numberop2;\n\n if (op1.ttisinteger() && op2.ttisinteger()) {\n L.stack[ra].setivalue(luaV_div(L, op1.value, op2.value));\n } else if ((numberop1 = tonumber(op1)) !== false && (numberop2 = tonumber(op2)) !== false) {\n L.stack[ra].setfltvalue(Math.floor(numberop1 / numberop2));\n } else {\n ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_IDIV);\n }\n break;\n }\n case OP_BAND: {\n let op1 = RKB(L, base, k, i);\n let op2 = RKC(L, base, k, i);\n let numberop1, numberop2;\n\n if ((numberop1 = tointeger(op1)) !== false && (numberop2 = tointeger(op2)) !== false) {\n L.stack[ra].setivalue(numberop1 & numberop2);\n } else {\n ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_BAND);\n }\n break;\n }\n case OP_BOR: {\n let op1 = RKB(L, base, k, i);\n let op2 = RKC(L, base, k, i);\n let numberop1, numberop2;\n\n if ((numberop1 = tointeger(op1)) !== false && (numberop2 = tointeger(op2)) !== false) {\n L.stack[ra].setivalue(numberop1 | numberop2);\n } else {\n ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_BOR);\n }\n break;\n }\n case OP_BXOR: {\n let op1 = RKB(L, base, k, i);\n let op2 = RKC(L, base, k, i);\n let numberop1, numberop2;\n\n if ((numberop1 = tointeger(op1)) !== false && (numberop2 = tointeger(op2)) !== false) {\n L.stack[ra].setivalue(numberop1 ^ numberop2);\n } else {\n ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_BXOR);\n }\n break;\n }\n case OP_SHL: {\n let op1 = RKB(L, base, k, i);\n let op2 = RKC(L, base, k, i);\n let numberop1, numberop2;\n\n if ((numberop1 = tointeger(op1)) !== false && (numberop2 = tointeger(op2)) !== false) {\n L.stack[ra].setivalue(luaV_shiftl(numberop1, numberop2));\n } else {\n ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_SHL);\n }\n break;\n }\n case OP_SHR: {\n let op1 = RKB(L, base, k, i);\n let op2 = RKC(L, base, k, i);\n let numberop1, numberop2;\n\n if ((numberop1 = tointeger(op1)) !== false && (numberop2 = tointeger(op2)) !== false) {\n L.stack[ra].setivalue(luaV_shiftl(numberop1, -numberop2));\n } else {\n ltm.luaT_trybinTM(L, op1, op2, L.stack[ra], ltm.TMS.TM_SHR);\n }\n break;\n }\n case OP_UNM: {\n let op = L.stack[RB(L, base, i)];\n let numberop;\n\n if (op.ttisinteger()) {\n L.stack[ra].setivalue((-op.value)|0);\n } else if ((numberop = tonumber(op)) !== false) {\n L.stack[ra].setfltvalue(-numberop);\n } else {\n ltm.luaT_trybinTM(L, op, op, L.stack[ra], ltm.TMS.TM_UNM);\n }\n break;\n }\n case OP_BNOT: {\n let op = L.stack[RB(L, base, i)];\n\n if (op.ttisinteger()) {\n L.stack[ra].setivalue(~op.value);\n } else {\n ltm.luaT_trybinTM(L, op, op, L.stack[ra], ltm.TMS.TM_BNOT);\n }\n break;\n }\n case OP_NOT: {\n let op = L.stack[RB(L, base, i)];\n L.stack[ra].setbvalue(op.l_isfalse());\n break;\n }\n case OP_LEN: {\n luaV_objlen(L, L.stack[ra], L.stack[RB(L, base, i)]);\n break;\n }\n case OP_CONCAT: {\n let b = i.B;\n let c = i.C;\n L.top = base + c + 1; /* mark the end of concat operands */\n luaV_concat(L, c - b + 1);\n let rb = base + b;\n lobject.setobjs2s(L, ra, rb);\n ldo.adjust_top(L, ci.top); /* restore top */\n break;\n }\n case OP_JMP: {\n dojump(L, ci, i, 0);\n break;\n }\n case OP_EQ: {\n if (luaV_equalobj(L, RKB(L, base, k, i), RKC(L, base, k, i)) !== i.A)\n ci.l_savedpc++;\n else\n donextjump(L, ci);\n break;\n }\n case OP_LT: {\n if (luaV_lessthan(L, RKB(L, base, k, i), RKC(L, base, k, i)) !== i.A)\n ci.l_savedpc++;\n else\n donextjump(L, ci);\n break;\n }\n case OP_LE: {\n if (luaV_lessequal(L, RKB(L, base, k, i), RKC(L, base, k, i)) !== i.A)\n ci.l_savedpc++;\n else\n donextjump(L, ci);\n break;\n }\n case OP_TEST: {\n if (i.C ? L.stack[ra].l_isfalse() : !L.stack[ra].l_isfalse())\n ci.l_savedpc++;\n else\n donextjump(L, ci);\n break;\n }\n case OP_TESTSET: {\n let rbIdx = RB(L, base, i);\n let rb = L.stack[rbIdx];\n if (i.C ? rb.l_isfalse() : !rb.l_isfalse())\n ci.l_savedpc++;\n else {\n lobject.setobjs2s(L, ra, rbIdx);\n donextjump(L, ci);\n }\n break;\n }\n case OP_CALL: {\n let b = i.B;\n let nresults = i.C - 1;\n if (b !== 0) ldo.adjust_top(L, ra+b); /* else previous instruction set top */\n if (ldo.luaD_precall(L, ra, nresults)) {\n if (nresults >= 0)\n ldo.adjust_top(L, ci.top); /* adjust results */\n } else {\n ci = L.ci;\n continue newframe;\n }\n\n break;\n }\n case OP_TAILCALL: {\n let b = i.B;\n if (b !== 0) ldo.adjust_top(L, ra+b); /* else previous instruction set top */\n if (ldo.luaD_precall(L, ra, LUA_MULTRET)) { // JS function\n } else {\n /* tail call: put called frame (n) in place of caller one (o) */\n let nci = L.ci;\n let oci = nci.previous;\n let nfunc = nci.func;\n let nfuncOff = nci.funcOff;\n let ofuncOff = oci.funcOff;\n let lim = nci.l_base + nfunc.value.p.numparams;\n if (cl.p.p.length > 0) lfunc.luaF_close(L, oci.l_base);\n for (let aux = 0; nfuncOff + aux < lim; aux++)\n lobject.setobjs2s(L, ofuncOff + aux, nfuncOff + aux);\n oci.l_base = ofuncOff + (nci.l_base - nfuncOff);\n oci.top = ofuncOff + (L.top - nfuncOff);\n ldo.adjust_top(L, oci.top); /* correct top */\n oci.l_code = nci.l_code;\n oci.l_savedpc = nci.l_savedpc;\n oci.callstatus |= lstate.CIST_TAIL;\n oci.next = null;\n ci = L.ci = oci;\n\n lua_assert(L.top === oci.l_base + L.stack[ofuncOff].value.p.maxstacksize);\n\n continue newframe;\n }\n break;\n }\n case OP_RETURN: {\n if (cl.p.p.length > 0) lfunc.luaF_close(L, base);\n let b = ldo.luaD_poscall(L, ci, ra, (i.B !== 0 ? i.B - 1 : L.top - ra));\n\n if (ci.callstatus & lstate.CIST_FRESH)\n return; /* external invocation: return */\n /* invocation via reentry: continue execution */\n ci = L.ci;\n if (b) ldo.adjust_top(L, ci.top);\n lua_assert(ci.callstatus & lstate.CIST_LUA);\n lua_assert(ci.l_code[ci.l_savedpc - 1].opcode === OP_CALL);\n continue newframe;\n }\n case OP_FORLOOP: {\n if (L.stack[ra].ttisinteger()) { /* integer loop? */\n let step = L.stack[ra + 2].value;\n let idx = (L.stack[ra].value + step)|0;\n let limit = L.stack[ra + 1].value;\n\n if (0 < step ? idx <= limit : limit <= idx) {\n ci.l_savedpc += i.sBx;\n L.stack[ra].chgivalue(idx); /* update internal index... */\n L.stack[ra + 3].setivalue(idx);\n }\n } else { /* floating loop */\n let step = L.stack[ra + 2].value;\n let idx = L.stack[ra].value + step;\n let limit = L.stack[ra + 1].value;\n\n if (0 < step ? idx <= limit : limit <= idx) {\n ci.l_savedpc += i.sBx;\n L.stack[ra].chgfltvalue(idx); /* update internal index... */\n L.stack[ra + 3].setfltvalue(idx);\n }\n }\n break;\n }\n case OP_FORPREP: {\n let init = L.stack[ra];\n let plimit = L.stack[ra + 1];\n let pstep = L.stack[ra + 2];\n let forlim;\n\n if (init.ttisinteger() && pstep.ttisinteger() && (forlim = forlimit(plimit, pstep.value))) {\n /* all values are integer */\n let initv = forlim.stopnow ? 0 : init.value;\n plimit.value = forlim.ilimit;\n init.value = (initv - pstep.value)|0;\n } else { /* try making all values floats */\n let nlimit, nstep, ninit;\n if ((nlimit = tonumber(plimit)) === false)\n ldebug.luaG_runerror(L, to_luastring(\"'for' limit must be a number\", true));\n L.stack[ra + 1].setfltvalue(nlimit);\n if ((nstep = tonumber(pstep)) === false)\n ldebug.luaG_runerror(L, to_luastring(\"'for' step must be a number\", true));\n L.stack[ra + 2].setfltvalue(nstep);\n if ((ninit = tonumber(init)) === false)\n ldebug.luaG_runerror(L, to_luastring(\"'for' initial value must be a number\", true));\n L.stack[ra].setfltvalue(ninit - nstep);\n }\n\n ci.l_savedpc += i.sBx;\n break;\n }\n case OP_TFORCALL: {\n let cb = ra + 3; /* call base */\n lobject.setobjs2s(L, cb+2, ra+2);\n lobject.setobjs2s(L, cb+1, ra+1);\n lobject.setobjs2s(L, cb, ra);\n ldo.adjust_top(L, cb+3); /* func. + 2 args (state and index) */\n ldo.luaD_call(L, cb, i.C);\n ldo.adjust_top(L, ci.top);\n /* go straight to OP_TFORLOOP */\n i = ci.l_code[ci.l_savedpc++];\n ra = RA(L, base, i);\n lua_assert(i.opcode === OP_TFORLOOP);\n }\n /* fall through */\n case OP_TFORLOOP: {\n if (!L.stack[ra + 1].ttisnil()) { /* continue loop? */\n lobject.setobjs2s(L, ra, ra + 1); /* save control variable */\n ci.l_savedpc += i.sBx; /* jump back */\n }\n break;\n }\n case OP_SETLIST: {\n let n = i.B;\n let c = i.C;\n\n if (n === 0) n = L.top - ra - 1;\n\n if (c === 0) {\n lua_assert(ci.l_code[ci.l_savedpc].opcode === OP_EXTRAARG);\n c = ci.l_code[ci.l_savedpc++].Ax;\n }\n\n let h = L.stack[ra].value;\n let last = ((c - 1) * LFIELDS_PER_FLUSH) + n;\n\n for (; n > 0; n--) {\n ltable.luaH_setint(h, last--, L.stack[ra + n]);\n }\n ldo.adjust_top(L, ci.top); /* correct top (in case of previous open call) */\n break;\n }\n case OP_CLOSURE: {\n let p = cl.p.p[i.Bx];\n let ncl = getcached(p, cl.upvals, L.stack, base); /* cached closure */\n if (ncl === null) /* no match? */\n pushclosure(L, p, cl.upvals, base, ra); /* create a new one */\n else\n L.stack[ra].setclLvalue(ncl);\n break;\n }\n case OP_VARARG: {\n let b = i.B - 1;\n let n = base - ci.funcOff - cl.p.numparams - 1;\n let j;\n\n if (n < 0) /* less arguments than parameters? */\n n = 0; /* no vararg arguments */\n\n if (b < 0) {\n b = n; /* get all var. arguments */\n ldo.luaD_checkstack(L, n);\n ldo.adjust_top(L, ra + n);\n }\n\n for (j = 0; j < b && j < n; j++)\n lobject.setobjs2s(L, ra + j, base - n + j);\n\n for (; j < b; j++) /* complete required results with nil */\n L.stack[ra + j].setnilvalue();\n break;\n }\n case OP_EXTRAARG: {\n throw Error(\"invalid opcode\");\n }\n }\n }\n};\n\nconst dojump = function(L, ci, i, e) {\n let a = i.A;\n if (a !== 0) lfunc.luaF_close(L, ci.l_base + a - 1);\n ci.l_savedpc += i.sBx + e;\n};\n\nconst donextjump = function(L, ci) {\n dojump(L, ci, ci.l_code[ci.l_savedpc], 1);\n};\n\n\nconst luaV_lessthan = function(L, l, r) {\n if (l.ttisnumber() && r.ttisnumber())\n return LTnum(l, r) ? 1 : 0;\n else if (l.ttisstring() && r.ttisstring())\n return l_strcmp(l.tsvalue(), r.tsvalue()) < 0 ? 1 : 0;\n else {\n let res = ltm.luaT_callorderTM(L, l, r, ltm.TMS.TM_LT);\n if (res === null)\n ldebug.luaG_ordererror(L, l, r);\n return res ? 1 : 0;\n }\n};\n\nconst luaV_lessequal = function(L, l, r) {\n let res;\n\n if (l.ttisnumber() && r.ttisnumber())\n return LEnum(l, r) ? 1 : 0;\n else if (l.ttisstring() && r.ttisstring())\n return l_strcmp(l.tsvalue(), r.tsvalue()) <= 0 ? 1 : 0;\n else {\n res = ltm.luaT_callorderTM(L, l, r, ltm.TMS.TM_LE);\n if (res !== null)\n return res ? 1 : 0;\n }\n /* try 'lt': */\n L.ci.callstatus |= lstate.CIST_LEQ; /* mark it is doing 'lt' for 'le' */\n res = ltm.luaT_callorderTM(L, r, l, ltm.TMS.TM_LT);\n L.ci.callstatus ^= lstate.CIST_LEQ; /* clear mark */\n if (res === null)\n ldebug.luaG_ordererror(L, l, r);\n return res ? 0 : 1; /* result is negated */\n};\n\nconst luaV_equalobj = function(L, t1, t2) {\n if (t1.ttype() !== t2.ttype()) { /* not the same variant? */\n if (t1.ttnov() !== t2.ttnov() || t1.ttnov() !== LUA_TNUMBER)\n return 0; /* only numbers can be equal with different variants */\n else { /* two numbers with different variants */\n /* OPTIMIZATION: instead of calling luaV_tointeger we can just let JS do the comparison */\n return (t1.value === t2.value) ? 1 : 0;\n }\n }\n\n let tm;\n\n /* values have same type and same variant */\n switch(t1.ttype()) {\n case LUA_TNIL:\n return 1;\n case LUA_TBOOLEAN:\n return t1.value == t2.value ? 1 : 0; // Might be 1 or true\n case LUA_TLIGHTUSERDATA:\n case LUA_TNUMINT:\n case LUA_TNUMFLT:\n case LUA_TLCF:\n return t1.value === t2.value ? 1 : 0;\n case LUA_TSHRSTR:\n case LUA_TLNGSTR: {\n return luaS_eqlngstr(t1.tsvalue(), t2.tsvalue()) ? 1 : 0;\n }\n case LUA_TUSERDATA:\n case LUA_TTABLE:\n if (t1.value === t2.value) return 1;\n else if (L === null) return 0;\n\n tm = ltm.fasttm(L, t1.value.metatable, ltm.TMS.TM_EQ);\n if (tm === null)\n tm = ltm.fasttm(L, t2.value.metatable, ltm.TMS.TM_EQ);\n break;\n default:\n return t1.value === t2.value ? 1 : 0;\n }\n\n if (tm === null) /* no TM? */\n return 0;\n\n let tv = new lobject.TValue(); /* doesn't use the stack */\n ltm.luaT_callTM(L, tm, t1, t2, tv, 1);\n return tv.l_isfalse() ? 0 : 1;\n};\n\nconst luaV_rawequalobj = function(t1, t2) {\n return luaV_equalobj(null, t1, t2);\n};\n\nconst forlimit = function(obj, step) {\n let stopnow = false;\n let ilimit = luaV_tointeger(obj, step < 0 ? 2 : 1);\n if (ilimit === false) {\n let n = tonumber(obj);\n if (n === false)\n return false;\n\n if (0 < n) {\n ilimit = LUA_MAXINTEGER;\n if (step < 0) stopnow = true;\n } else {\n ilimit = LUA_MININTEGER;\n if (step >= 0) stopnow = true;\n }\n }\n\n return {\n stopnow: stopnow,\n ilimit: ilimit\n };\n};\n\n/*\n** try to convert a value to an integer, rounding according to 'mode':\n** mode === 0: accepts only integral values\n** mode === 1: takes the floor of the number\n** mode === 2: takes the ceil of the number\n*/\nconst luaV_tointeger = function(obj, mode) {\n if (obj.ttisfloat()) {\n let n = obj.value;\n let f = Math.floor(n);\n\n if (n !== f) { /* not an integral value? */\n if (mode === 0)\n return false; /* fails if mode demands integral value */\n else if (mode > 1) /* needs ceil? */\n f += 1; /* convert floor to ceil (remember: n !== f) */\n }\n\n return lua_numbertointeger(f);\n } else if (obj.ttisinteger()) {\n return obj.value;\n } else if (cvt2num(obj)) {\n let v = new lobject.TValue();\n if (lobject.luaO_str2num(obj.svalue(), v) === (obj.vslen() + 1))\n return luaV_tointeger(v, mode);\n }\n\n return false;\n};\n\nconst tointeger = function(o) {\n return o.ttisinteger() ? o.value : luaV_tointeger(o, 0);\n};\n\nconst tonumber = function(o) {\n if (o.ttnov() === LUA_TNUMBER)\n return o.value;\n\n if (cvt2num(o)) { /* string convertible to number? */\n let v = new lobject.TValue();\n if (lobject.luaO_str2num(o.svalue(), v) === (o.vslen() + 1))\n return v.value;\n }\n\n return false;\n};\n\n/*\n** Return 'l < r', for numbers.\n** As fengari uses javascript numbers for both floats and integers and has\n** correct semantics, we can just compare values.\n*/\nconst LTnum = function(l, r) {\n return l.value < r.value;\n};\n\n/*\n** Return 'l <= r', for numbers.\n*/\nconst LEnum = function(l, r) {\n return l.value <= r.value;\n};\n\n/*\n** Compare two strings 'ls' x 'rs', returning an integer smaller-equal-\n** -larger than zero if 'ls' is smaller-equal-larger than 'rs'.\n*/\nconst l_strcmp = function(ls, rs) {\n let l = luaS_hashlongstr(ls);\n let r = luaS_hashlongstr(rs);\n /* In fengari we assume string hash has same collation as byte values */\n if (l === r)\n return 0;\n else if (l < r)\n return -1;\n else\n return 1;\n};\n\n/*\n** Main operation 'ra' = #rb'.\n*/\nconst luaV_objlen = function(L, ra, rb) {\n let tm;\n switch(rb.ttype()) {\n case LUA_TTABLE: {\n let h = rb.value;\n tm = ltm.fasttm(L, h.metatable, ltm.TMS.TM_LEN);\n if (tm !== null) break; /* metamethod? break switch to call it */\n ra.setivalue(ltable.luaH_getn(h)); /* else primitive len */\n return;\n }\n case LUA_TSHRSTR:\n case LUA_TLNGSTR:\n ra.setivalue(rb.vslen());\n return;\n default: {\n tm = ltm.luaT_gettmbyobj(L, rb, ltm.TMS.TM_LEN);\n if (tm.ttisnil())\n ldebug.luaG_typeerror(L, rb, to_luastring(\"get length of\", true));\n break;\n }\n }\n\n ltm.luaT_callTM(L, tm, rb, rb, ra, 1);\n};\n\n/* Shim taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul */\nconst luaV_imul = Math.imul || function(a, b) {\n let aHi = (a >>> 16) & 0xffff;\n let aLo = a & 0xffff;\n let bHi = (b >>> 16) & 0xffff;\n let bLo = b & 0xffff;\n /*\n ** the shift by 0 fixes the sign on the high part\n ** the final |0 converts the unsigned value into a signed value\n */\n return ((aLo * bLo) + (((aHi * bLo + aLo * bHi) << 16) >>> 0) | 0);\n};\n\nconst luaV_div = function(L, m, n) {\n if (n === 0)\n ldebug.luaG_runerror(L, to_luastring(\"attempt to divide by zero\"));\n return Math.floor(m / n)|0;\n};\n\n// % semantic on negative numbers is different in js\nconst luaV_mod = function(L, m, n) {\n if (n === 0)\n ldebug.luaG_runerror(L, to_luastring(\"attempt to perform 'n%%0'\"));\n return (m - Math.floor(m / n) * n)|0;\n};\n\nconst NBITS = 32;\n\nconst luaV_shiftl = function(x, y) {\n if (y < 0) { /* shift right? */\n if (y <= -NBITS) return 0;\n else return x >>> -y;\n }\n else { /* shift left */\n if (y >= NBITS) return 0;\n else return x << y;\n }\n};\n\n/*\n** check whether cached closure in prototype 'p' may be reused, that is,\n** whether there is a cached closure with the same upvalues needed by\n** new closure to be created.\n*/\nconst getcached = function(p, encup, stack, base) {\n let c = p.cache;\n if (c !== null) { /* is there a cached closure? */\n let uv = p.upvalues;\n let nup = uv.length;\n for (let i = 0; i < nup; i++) { /* check whether it has right upvalues */\n let v = uv[i].instack ? stack[base + uv[i].idx] : encup[uv[i].idx];\n if (c.upvals[i] !== v)\n return null; /* wrong upvalue; cannot reuse closure */\n }\n }\n return c; /* return cached closure (or NULL if no cached closure) */\n};\n\n/*\n** create a new Lua closure, push it in the stack, and initialize\n** its upvalues.\n*/\nconst pushclosure = function(L, p, encup, base, ra) {\n let nup = p.upvalues.length;\n let uv = p.upvalues;\n let ncl = new lobject.LClosure(L, nup);\n ncl.p = p;\n L.stack[ra].setclLvalue(ncl);\n for (let i = 0; i < nup; i++) {\n if (uv[i].instack)\n ncl.upvals[i] = lfunc.luaF_findupval(L, base + uv[i].idx);\n else\n ncl.upvals[i] = encup[uv[i].idx];\n }\n p.cache = ncl; /* save it on cache for reuse */\n};\n\nconst cvt2str = function(o) {\n return o.ttisnumber();\n};\n\nconst cvt2num = function(o) {\n return o.ttisstring();\n};\n\nconst tostring = function(L, i) {\n let o = L.stack[i];\n\n if (o.ttisstring()) return true;\n\n if (cvt2str(o)) {\n lobject.luaO_tostring(L, o);\n return true;\n }\n\n return false;\n};\n\nconst isemptystr = function(o) {\n return o.ttisstring() && o.vslen() === 0;\n};\n\n/* copy strings in stack from top - n up to top - 1 to buffer */\nconst copy2buff = function(L, top, n, buff) {\n let tl = 0; /* size already copied */\n do {\n let tv = L.stack[top-n];\n let l = tv.vslen(); /* length of string being copied */\n let s = tv.svalue();\n buff.set(s, tl);\n tl += l;\n } while (--n > 0);\n};\n\n/*\n** Main operation for concatenation: concat 'total' values in the stack,\n** from 'L->top - total' up to 'L->top - 1'.\n*/\nconst luaV_concat = function(L, total) {\n lua_assert(total >= 2);\n do {\n let top = L.top;\n let n = 2; /* number of elements handled in this pass (at least 2) */\n\n if (!(L.stack[top-2].ttisstring() || cvt2str(L.stack[top-2])) || !tostring(L, top - 1)) {\n ltm.luaT_trybinTM(L, L.stack[top-2], L.stack[top-1], L.stack[top-2], ltm.TMS.TM_CONCAT);\n } else if (isemptystr(L.stack[top-1])) {\n tostring(L, top - 2);\n } else if (isemptystr(L.stack[top-2])) {\n lobject.setobjs2s(L, top - 2, top - 1);\n } else {\n /* at least two non-empty string values; get as many as possible */\n let tl = L.stack[top-1].vslen();\n /* collect total length and number of strings */\n for (n = 1; n < total && tostring(L, top - n - 1); n++) {\n let l = L.stack[top - n - 1].vslen();\n tl += l;\n }\n let buff = new Uint8Array(tl);\n copy2buff(L, top, n, buff);\n let ts = luaS_bless(L, buff);\n lobject.setsvalue2s(L, top - n, ts);\n }\n total -= n - 1; /* got 'n' strings to create 1 new */\n /* popped 'n' strings and pushed one */\n for (; L.top > top-(n-1);)\n delete L.stack[--L.top];\n } while (total > 1); /* repeat until only 1 result left */\n};\n\nconst MAXTAGLOOP = 2000;\n\nconst luaV_gettable = function(L, t, key, ra) {\n for (let loop = 0; loop < MAXTAGLOOP; loop++) {\n let tm;\n\n if (!t.ttistable()) {\n tm = ltm.luaT_gettmbyobj(L, t, ltm.TMS.TM_INDEX);\n if (tm.ttisnil())\n ldebug.luaG_typeerror(L, t, to_luastring('index', true)); /* no metamethod */\n /* else will try the metamethod */\n } else {\n let slot = ltable.luaH_get(L, t.value, key);\n if (!slot.ttisnil()) {\n lobject.setobj2s(L, ra, slot);\n return;\n } else { /* 't' is a table */\n tm = ltm.fasttm(L, t.value.metatable, ltm.TMS.TM_INDEX); /* table's metamethod */\n if (tm === null) { /* no metamethod? */\n L.stack[ra].setnilvalue(); /* result is nil */\n return;\n }\n }\n /* else will try the metamethod */\n }\n if (tm.ttisfunction()) { /* is metamethod a function? */\n ltm.luaT_callTM(L, tm, t, key, L.stack[ra], 1); /* call it */\n return;\n }\n t = tm; /* else try to access 'tm[key]' */\n }\n\n ldebug.luaG_runerror(L, to_luastring(\"'__index' chain too long; possible loop\", true));\n};\n\nconst settable = function(L, t, key, val) {\n for (let loop = 0; loop < MAXTAGLOOP; loop++) {\n let tm;\n if (t.ttistable()) {\n let h = t.value; /* save 't' table */\n let slot = ltable.luaH_get(L, h, key);\n if (!slot.ttisnil() || (tm = ltm.fasttm(L, h.metatable, ltm.TMS.TM_NEWINDEX)) === null) {\n ltable.luaH_setfrom(L, h, key, val);\n ltable.invalidateTMcache(h);\n return;\n }\n /* else will try the metamethod */\n } else { /* not a table; check metamethod */\n if ((tm = ltm.luaT_gettmbyobj(L, t, ltm.TMS.TM_NEWINDEX)).ttisnil())\n ldebug.luaG_typeerror(L, t, to_luastring('index', true));\n }\n /* try the metamethod */\n if (tm.ttisfunction()) {\n ltm.luaT_callTM(L, tm, t, key, val, 0);\n return;\n }\n t = tm; /* else repeat assignment over 'tm' */\n }\n\n ldebug.luaG_runerror(L, to_luastring(\"'__newindex' chain too long; possible loop\", true));\n};\n\n\nmodule.exports.cvt2str = cvt2str;\nmodule.exports.cvt2num = cvt2num;\nmodule.exports.luaV_gettable = luaV_gettable;\nmodule.exports.luaV_concat = luaV_concat;\nmodule.exports.luaV_div = luaV_div;\nmodule.exports.luaV_equalobj = luaV_equalobj;\nmodule.exports.luaV_execute = luaV_execute;\nmodule.exports.luaV_finishOp = luaV_finishOp;\nmodule.exports.luaV_imul = luaV_imul;\nmodule.exports.luaV_lessequal = luaV_lessequal;\nmodule.exports.luaV_lessthan = luaV_lessthan;\nmodule.exports.luaV_mod = luaV_mod;\nmodule.exports.luaV_objlen = luaV_objlen;\nmodule.exports.luaV_rawequalobj = luaV_rawequalobj;\nmodule.exports.luaV_shiftl = luaV_shiftl;\nmodule.exports.luaV_tointeger = luaV_tointeger;\nmodule.exports.settable = settable;\nmodule.exports.tointeger = tointeger;\nmodule.exports.tonumber = tonumber;\n","\"use strict\";\n\nconst OpCodes = [\n \"MOVE\",\n \"LOADK\",\n \"LOADKX\",\n \"LOADBOOL\",\n \"LOADNIL\",\n \"GETUPVAL\",\n \"GETTABUP\",\n \"GETTABLE\",\n \"SETTABUP\",\n \"SETUPVAL\",\n \"SETTABLE\",\n \"NEWTABLE\",\n \"SELF\",\n \"ADD\",\n \"SUB\",\n \"MUL\",\n \"MOD\",\n \"POW\",\n \"DIV\",\n \"IDIV\",\n \"BAND\",\n \"BOR\",\n \"BXOR\",\n \"SHL\",\n \"SHR\",\n \"UNM\",\n \"BNOT\",\n \"NOT\",\n \"LEN\",\n \"CONCAT\",\n \"JMP\",\n \"EQ\",\n \"LT\",\n \"LE\",\n \"TEST\",\n \"TESTSET\",\n \"CALL\",\n \"TAILCALL\",\n \"RETURN\",\n \"FORLOOP\",\n \"FORPREP\",\n \"TFORCALL\",\n \"TFORLOOP\",\n \"SETLIST\",\n \"CLOSURE\",\n \"VARARG\",\n \"EXTRAARG\"\n];\n\nconst OpCodesI = {\n OP_MOVE: 0,\n OP_LOADK: 1,\n OP_LOADKX: 2,\n OP_LOADBOOL: 3,\n OP_LOADNIL: 4,\n OP_GETUPVAL: 5,\n OP_GETTABUP: 6,\n OP_GETTABLE: 7,\n OP_SETTABUP: 8,\n OP_SETUPVAL: 9,\n OP_SETTABLE: 10,\n OP_NEWTABLE: 11,\n OP_SELF: 12,\n OP_ADD: 13,\n OP_SUB: 14,\n OP_MUL: 15,\n OP_MOD: 16,\n OP_POW: 17,\n OP_DIV: 18,\n OP_IDIV: 19,\n OP_BAND: 20,\n OP_BOR: 21,\n OP_BXOR: 22,\n OP_SHL: 23,\n OP_SHR: 24,\n OP_UNM: 25,\n OP_BNOT: 26,\n OP_NOT: 27,\n OP_LEN: 28,\n OP_CONCAT: 29,\n OP_JMP: 30,\n OP_EQ: 31,\n OP_LT: 32,\n OP_LE: 33,\n OP_TEST: 34,\n OP_TESTSET: 35,\n OP_CALL: 36,\n OP_TAILCALL: 37,\n OP_RETURN: 38,\n OP_FORLOOP: 39,\n OP_FORPREP: 40,\n OP_TFORCALL: 41,\n OP_TFORLOOP: 42,\n OP_SETLIST: 43,\n OP_CLOSURE: 44,\n OP_VARARG: 45,\n OP_EXTRAARG: 46\n};\n\n/*\n** masks for instruction properties. The format is:\n** bits 0-1: op mode\n** bits 2-3: C arg mode\n** bits 4-5: B arg mode\n** bit 6: instruction set register A\n** bit 7: operator is a test (next instruction must be a jump)\n*/\nconst OpArgN = 0; /* argument is not used */\nconst OpArgU = 1; /* argument is used */\nconst OpArgR = 2; /* argument is a register or a jump offset */\nconst OpArgK = 3; /* argument is a constant or register/constant */\n\n/* basic instruction format */\nconst iABC = 0;\nconst iABx = 1;\nconst iAsBx = 2;\nconst iAx = 3;\n\nconst luaP_opmodes = [\n 0 << 7 | 1 << 6 | OpArgR << 4 | OpArgN << 2 | iABC, /* OP_MOVE */\n 0 << 7 | 1 << 6 | OpArgK << 4 | OpArgN << 2 | iABx, /* OP_LOADK */\n 0 << 7 | 1 << 6 | OpArgN << 4 | OpArgN << 2 | iABx, /* OP_LOADKX */\n 0 << 7 | 1 << 6 | OpArgU << 4 | OpArgU << 2 | iABC, /* OP_LOADBOOL */\n 0 << 7 | 1 << 6 | OpArgU << 4 | OpArgN << 2 | iABC, /* OP_LOADNIL */\n 0 << 7 | 1 << 6 | OpArgU << 4 | OpArgN << 2 | iABC, /* OP_GETUPVAL */\n 0 << 7 | 1 << 6 | OpArgU << 4 | OpArgK << 2 | iABC, /* OP_GETTABUP */\n 0 << 7 | 1 << 6 | OpArgR << 4 | OpArgK << 2 | iABC, /* OP_GETTABLE */\n 0 << 7 | 0 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_SETTABUP */\n 0 << 7 | 0 << 6 | OpArgU << 4 | OpArgN << 2 | iABC, /* OP_SETUPVAL */\n 0 << 7 | 0 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_SETTABLE */\n 0 << 7 | 1 << 6 | OpArgU << 4 | OpArgU << 2 | iABC, /* OP_NEWTABLE */\n 0 << 7 | 1 << 6 | OpArgR << 4 | OpArgK << 2 | iABC, /* OP_SELF */\n 0 << 7 | 1 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_ADD */\n 0 << 7 | 1 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_SUB */\n 0 << 7 | 1 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_MUL */\n 0 << 7 | 1 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_MOD */\n 0 << 7 | 1 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_POW */\n 0 << 7 | 1 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_DIV */\n 0 << 7 | 1 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_IDIV */\n 0 << 7 | 1 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_BAND */\n 0 << 7 | 1 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_BOR */\n 0 << 7 | 1 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_BXOR */\n 0 << 7 | 1 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_SHL */\n 0 << 7 | 1 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_SHR */\n 0 << 7 | 1 << 6 | OpArgR << 4 | OpArgN << 2 | iABC, /* OP_UNM */\n 0 << 7 | 1 << 6 | OpArgR << 4 | OpArgN << 2 | iABC, /* OP_BNOT */\n 0 << 7 | 1 << 6 | OpArgR << 4 | OpArgN << 2 | iABC, /* OP_NOT */\n 0 << 7 | 1 << 6 | OpArgR << 4 | OpArgN << 2 | iABC, /* OP_LEN */\n 0 << 7 | 1 << 6 | OpArgR << 4 | OpArgR << 2 | iABC, /* OP_CONCAT */\n 0 << 7 | 0 << 6 | OpArgR << 4 | OpArgN << 2 | iAsBx, /* OP_JMP */\n 1 << 7 | 0 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_EQ */\n 1 << 7 | 0 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_LT */\n 1 << 7 | 0 << 6 | OpArgK << 4 | OpArgK << 2 | iABC, /* OP_LE */\n 1 << 7 | 0 << 6 | OpArgN << 4 | OpArgU << 2 | iABC, /* OP_TEST */\n 1 << 7 | 1 << 6 | OpArgR << 4 | OpArgU << 2 | iABC, /* OP_TESTSET */\n 0 << 7 | 1 << 6 | OpArgU << 4 | OpArgU << 2 | iABC, /* OP_CALL */\n 0 << 7 | 1 << 6 | OpArgU << 4 | OpArgU << 2 | iABC, /* OP_TAILCALL */\n 0 << 7 | 0 << 6 | OpArgU << 4 | OpArgN << 2 | iABC, /* OP_RETURN */\n 0 << 7 | 1 << 6 | OpArgR << 4 | OpArgN << 2 | iAsBx, /* OP_FORLOOP */\n 0 << 7 | 1 << 6 | OpArgR << 4 | OpArgN << 2 | iAsBx, /* OP_FORPREP */\n 0 << 7 | 0 << 6 | OpArgN << 4 | OpArgU << 2 | iABC, /* OP_TFORCALL */\n 0 << 7 | 1 << 6 | OpArgR << 4 | OpArgN << 2 | iAsBx, /* OP_TFORLOOP */\n 0 << 7 | 0 << 6 | OpArgU << 4 | OpArgU << 2 | iABC, /* OP_SETLIST */\n 0 << 7 | 1 << 6 | OpArgU << 4 | OpArgN << 2 | iABx, /* OP_CLOSURE */\n 0 << 7 | 1 << 6 | OpArgU << 4 | OpArgN << 2 | iABC, /* OP_VARARG */\n 0 << 7 | 0 << 6 | OpArgU << 4 | OpArgU << 2 | iAx /* OP_EXTRAARG */\n];\n\nconst getOpMode = function(m) {\n return luaP_opmodes[m] & 3;\n};\n\nconst getBMode = function(m) {\n return (luaP_opmodes[m] >> 4) & 3;\n};\n\nconst getCMode = function(m) {\n return (luaP_opmodes[m] >> 2) & 3;\n};\n\nconst testAMode = function(m) {\n return luaP_opmodes[m] & (1 << 6);\n};\n\nconst testTMode = function(m) {\n return luaP_opmodes[m] & (1 << 7);\n};\n\nconst SIZE_C = 9;\nconst SIZE_B = 9;\nconst SIZE_Bx = (SIZE_C + SIZE_B);\nconst SIZE_A = 8;\nconst SIZE_Ax = (SIZE_C + SIZE_B + SIZE_A);\nconst SIZE_OP = 6;\nconst POS_OP = 0;\nconst POS_A = (POS_OP + SIZE_OP);\nconst POS_C = (POS_A + SIZE_A);\nconst POS_B = (POS_C + SIZE_C);\nconst POS_Bx = POS_C;\nconst POS_Ax = POS_A;\nconst MAXARG_Bx = ((1 << SIZE_Bx) - 1);\nconst MAXARG_sBx = (MAXARG_Bx >> 1); /* 'sBx' is signed */\nconst MAXARG_Ax = ((1<> POS_OP) & MASK1(SIZE_OP, 0),\n A: (ins >> POS_A) & MASK1(SIZE_A, 0),\n B: (ins >> POS_B) & MASK1(SIZE_B, 0),\n C: (ins >> POS_C) & MASK1(SIZE_C, 0),\n Bx: (ins >> POS_Bx) & MASK1(SIZE_Bx, 0),\n Ax: (ins >> POS_Ax) & MASK1(SIZE_Ax, 0),\n sBx: ((ins >> POS_Bx) & MASK1(SIZE_Bx, 0)) - MAXARG_sBx\n };\n } else {\n let i = ins.code;\n ins.opcode = (i >> POS_OP) & MASK1(SIZE_OP, 0);\n ins.A = (i >> POS_A) & MASK1(SIZE_A, 0);\n ins.B = (i >> POS_B) & MASK1(SIZE_B, 0);\n ins.C = (i >> POS_C) & MASK1(SIZE_C, 0);\n ins.Bx = (i >> POS_Bx) & MASK1(SIZE_Bx, 0);\n ins.Ax = (i >> POS_Ax) & MASK1(SIZE_Ax, 0);\n ins.sBx = ((i >> POS_Bx) & MASK1(SIZE_Bx, 0)) - MAXARG_sBx;\n return ins;\n }\n};\n\nconst CREATE_ABC = function(o, a, b, c) {\n return fullins(o << POS_OP | a << POS_A | b << POS_B | c << POS_C);\n};\n\nconst CREATE_ABx = function(o, a, bc) {\n return fullins(o << POS_OP | a << POS_A | bc << POS_Bx);\n};\n\nconst CREATE_Ax = function(o, a) {\n return fullins(o << POS_OP | a << POS_Ax);\n};\n\n/* number of list items to accumulate before a SETLIST instruction */\nconst LFIELDS_PER_FLUSH = 50;\n\nmodule.exports.BITRK = BITRK;\nmodule.exports.CREATE_ABC = CREATE_ABC;\nmodule.exports.CREATE_ABx = CREATE_ABx;\nmodule.exports.CREATE_Ax = CREATE_Ax;\nmodule.exports.GET_OPCODE = GET_OPCODE;\nmodule.exports.GETARG_A = GETARG_A;\nmodule.exports.GETARG_B = GETARG_B;\nmodule.exports.GETARG_C = GETARG_C;\nmodule.exports.GETARG_Bx = GETARG_Bx;\nmodule.exports.GETARG_Ax = GETARG_Ax;\nmodule.exports.GETARG_sBx = GETARG_sBx;\nmodule.exports.INDEXK = INDEXK;\nmodule.exports.ISK = ISK;\nmodule.exports.LFIELDS_PER_FLUSH = LFIELDS_PER_FLUSH;\nmodule.exports.MAXARG_A = MAXARG_A;\nmodule.exports.MAXARG_Ax = MAXARG_Ax;\nmodule.exports.MAXARG_B = MAXARG_B;\nmodule.exports.MAXARG_Bx = MAXARG_Bx;\nmodule.exports.MAXARG_C = MAXARG_C;\nmodule.exports.MAXARG_sBx = MAXARG_sBx;\nmodule.exports.MAXINDEXRK = MAXINDEXRK;\nmodule.exports.NO_REG = NO_REG;\nmodule.exports.OpArgK = OpArgK;\nmodule.exports.OpArgN = OpArgN;\nmodule.exports.OpArgR = OpArgR;\nmodule.exports.OpArgU = OpArgU;\nmodule.exports.OpCodes = OpCodes;\nmodule.exports.OpCodesI = OpCodesI;\nmodule.exports.POS_A = POS_A;\nmodule.exports.POS_Ax = POS_Ax;\nmodule.exports.POS_B = POS_B;\nmodule.exports.POS_Bx = POS_Bx;\nmodule.exports.POS_C = POS_C;\nmodule.exports.POS_OP = POS_OP;\nmodule.exports.RKASK = RKASK;\nmodule.exports.SETARG_A = SETARG_A;\nmodule.exports.SETARG_Ax = SETARG_Ax;\nmodule.exports.SETARG_B = SETARG_B;\nmodule.exports.SETARG_Bx = SETARG_Bx;\nmodule.exports.SETARG_C = SETARG_C;\nmodule.exports.SETARG_sBx = SETARG_sBx;\nmodule.exports.SET_OPCODE = SET_OPCODE;\nmodule.exports.SIZE_A = SIZE_A;\nmodule.exports.SIZE_Ax = SIZE_Ax;\nmodule.exports.SIZE_B = SIZE_B;\nmodule.exports.SIZE_Bx = SIZE_Bx;\nmodule.exports.SIZE_C = SIZE_C;\nmodule.exports.SIZE_OP = SIZE_OP;\nmodule.exports.fullins = fullins;\nmodule.exports.getBMode = getBMode;\nmodule.exports.getCMode = getCMode;\nmodule.exports.getOpMode = getOpMode;\nmodule.exports.iABC = iABC;\nmodule.exports.iABx = iABx;\nmodule.exports.iAsBx = iAsBx;\nmodule.exports.iAx = iAx;\nmodule.exports.testAMode = testAMode;\nmodule.exports.testTMode = testTMode;\n","\"use strict\";\n\nconst {\n LUA_VERSION_MAJOR,\n LUA_VERSION_MINOR\n} = require(\"./lua.js\");\n\nconst LUA_VERSUFFIX = \"_\" + LUA_VERSION_MAJOR + \"_\" + LUA_VERSION_MINOR;\nmodule.exports.LUA_VERSUFFIX = LUA_VERSUFFIX;\n\nmodule.exports.lua_assert = function(c) {};\n\nmodule.exports.luaopen_base = require(\"./lbaselib.js\").luaopen_base;\n\nconst LUA_COLIBNAME = \"coroutine\";\nmodule.exports.LUA_COLIBNAME = LUA_COLIBNAME;\nmodule.exports.luaopen_coroutine = require(\"./lcorolib.js\").luaopen_coroutine;\n\nconst LUA_TABLIBNAME = \"table\";\nmodule.exports.LUA_TABLIBNAME = LUA_TABLIBNAME;\nmodule.exports.luaopen_table = require(\"./ltablib.js\").luaopen_table;\n\nif (typeof process !== \"undefined\") {\n const LUA_IOLIBNAME = \"io\";\n module.exports.LUA_IOLIBNAME = LUA_IOLIBNAME;\n module.exports.luaopen_io = require(\"./liolib.js\").luaopen_io;\n}\n\nconst LUA_OSLIBNAME = \"os\";\nmodule.exports.LUA_OSLIBNAME = LUA_OSLIBNAME;\nmodule.exports.luaopen_os = require(\"./loslib.js\").luaopen_os;\n\nconst LUA_STRLIBNAME = \"string\";\nmodule.exports.LUA_STRLIBNAME = LUA_STRLIBNAME;\nmodule.exports.luaopen_string = require(\"./lstrlib.js\").luaopen_string;\n\nconst LUA_UTF8LIBNAME = \"utf8\";\nmodule.exports.LUA_UTF8LIBNAME = LUA_UTF8LIBNAME;\nmodule.exports.luaopen_utf8 = require(\"./lutf8lib.js\").luaopen_utf8;\n\nconst LUA_BITLIBNAME = \"bit32\";\nmodule.exports.LUA_BITLIBNAME = LUA_BITLIBNAME;\n// module.exports.luaopen_bit32 = require(\"./lbitlib.js\").luaopen_bit32;\n\nconst LUA_MATHLIBNAME = \"math\";\nmodule.exports.LUA_MATHLIBNAME = LUA_MATHLIBNAME;\nmodule.exports.luaopen_math = require(\"./lmathlib.js\").luaopen_math;\n\nconst LUA_DBLIBNAME = \"debug\";\nmodule.exports.LUA_DBLIBNAME = LUA_DBLIBNAME;\nmodule.exports.luaopen_debug = require(\"./ldblib.js\").luaopen_debug;\n\nconst LUA_LOADLIBNAME = \"package\";\nmodule.exports.LUA_LOADLIBNAME = LUA_LOADLIBNAME;\nmodule.exports.luaopen_package = require(\"./loadlib.js\").luaopen_package;\n\nconst LUA_FENGARILIBNAME = \"fengari\";\nmodule.exports.LUA_FENGARILIBNAME = LUA_FENGARILIBNAME;\nmodule.exports.luaopen_fengari = require(\"./fengarilib.js\").luaopen_fengari;\n\nconst linit = require('./linit.js');\nmodule.exports.luaL_openlibs = linit.luaL_openlibs;\n","\"use strict\";\n\nconst {\n\tlua,\n\tlauxlib,\n\tlualib,\n\tto_luastring\n} = require('fengari');\nconst {\n\tLUA_MULTRET,\n\tLUA_OK,\n\tLUA_REGISTRYINDEX,\n\tLUA_RIDX_MAINTHREAD,\n\tLUA_TBOOLEAN,\n\tLUA_TFUNCTION,\n\tLUA_TLIGHTUSERDATA,\n\tLUA_TNIL,\n\tLUA_TNONE,\n\tLUA_TNUMBER,\n\tLUA_TSTRING,\n\tLUA_TTABLE,\n\tLUA_TTHREAD,\n\tLUA_TUSERDATA,\n\tlua_atnativeerror,\n\tlua_call,\n\tlua_getfield,\n\tlua_gettable,\n\tlua_gettop,\n\tlua_isnil,\n\tlua_isproxy,\n\tlua_newuserdata,\n\tlua_pcall,\n\tlua_pop,\n\tlua_pushboolean,\n\tlua_pushcfunction,\n\tlua_pushinteger,\n\tlua_pushlightuserdata,\n\tlua_pushliteral,\n\tlua_pushnil,\n\tlua_pushnumber,\n\tlua_pushstring,\n\tlua_pushvalue,\n\tlua_rawgeti,\n\tlua_rawgetp,\n\tlua_rawsetp,\n\tlua_rotate,\n\tlua_setfield,\n\tlua_settable,\n\tlua_settop,\n\tlua_toboolean,\n\tlua_tojsstring,\n\tlua_tonumber,\n\tlua_toproxy,\n\tlua_tothread,\n\tlua_touserdata,\n\tlua_type\n} = lua;\nconst {\n\tluaL_argerror,\n\tluaL_checkany,\n\tluaL_checkoption,\n\tluaL_checkstack,\n\tluaL_checkudata,\n\tluaL_error,\n\tluaL_getmetafield,\n\tluaL_newlib,\n\tluaL_newmetatable,\n\tluaL_requiref,\n\tluaL_setfuncs,\n\tluaL_setmetatable,\n\tluaL_testudata,\n\tluaL_tolstring\n} = lauxlib;\nconst {\n\tluaopen_base\n} = lualib;\n\nconst FENGARI_INTEROP_VERSION_MAJOR = \"0\";\nconst FENGARI_INTEROP_VERSION_MINOR = \"1\";\nconst FENGARI_INTEROP_VERSION_NUM = 1;\nconst FENGARI_INTEROP_VERSION_RELEASE = \"2\";\nconst FENGARI_INTEROP_VERSION = FENGARI_INTEROP_VERSION_MAJOR + \".\" + FENGARI_INTEROP_VERSION_MINOR;\nconst FENGARI_INTEROP_RELEASE = FENGARI_INTEROP_VERSION + \".\" + FENGARI_INTEROP_VERSION_RELEASE;\n\nlet custom_inspect_symbol;\nif (typeof process !== \"undefined\") {\n\ttry { /* for node.js */\n\t\tcustom_inspect_symbol = require('util').inspect.custom;\n\t} catch (e) {}\n}\n\nconst global_env = (function() {\n\t/* global WorkerGlobalScope */ /* see https://github.com/sindresorhus/globals/issues/127 */\n\tif (typeof process !== \"undefined\") {\n\t\t/* node */\n\t\treturn global;\n\t} else if (typeof window !== \"undefined\") {\n\t\t/* browser window */\n\t\treturn window;\n\t} else if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {\n\t\t/* web worker */\n\t\treturn self;\n\t} else {\n\t\t/* unknown global env */\n\t\treturn (0, eval)('this'); /* use non-strict mode to get global env */\n\t}\n})();\n\nlet apply, construct, Reflect_deleteProperty;\nif (typeof Reflect !== \"undefined\") {\n\tapply = Reflect.apply;\n\tconstruct = Reflect.construct;\n\tReflect_deleteProperty = Reflect.deleteProperty;\n} else {\n\tconst fApply = Function.apply;\n\tconst bind = Function.bind;\n\tapply = function(target, thisArgument, argumentsList) {\n\t\treturn fApply.call(target, thisArgument, argumentsList);\n\t};\n\tconstruct = function(target, argumentsList /*, newTarget */) {\n\t\tswitch (argumentsList.length) {\n\t\t\tcase 0: return new target();\n\t\t\tcase 1: return new target(argumentsList[0]);\n\t\t\tcase 2: return new target(argumentsList[0], argumentsList[1]);\n\t\t\tcase 3: return new target(argumentsList[0], argumentsList[1], argumentsList[2]);\n\t\t\tcase 4: return new target(argumentsList[0], argumentsList[1], argumentsList[2], argumentsList[3]);\n\t\t}\n\t\tlet args = [null];\n\t\targs.push.apply(args, argumentsList);\n\t\treturn new (bind.apply(target, args))();\n\t};\n\t/* need to be in non-strict mode */\n\tReflect_deleteProperty = Function(\"t\", \"k\", \"delete t[k]\");\n}\n\n/*\nString.concat coerces to string with correct hint for Symbol.toPrimitive\n`this` isn't allowed to be null, so bind the empty string\n*/\nconst toString = String.prototype.concat.bind(\"\");\n\nconst isobject = function(o) {\n\treturn typeof o === \"object\" ? o !== null : typeof o === \"function\";\n};\n\nconst js_tname = to_luastring(\"js object\");\nconst js_library_not_loaded = \"js library not loaded into lua_State\";\n\nconst testjs = function(L, idx) {\n\tlet u = luaL_testudata(L, idx, js_tname);\n\tif (u)\n\t\treturn u.data;\n\telse\n\t\treturn void 0;\n};\n\nconst checkjs = function(L, idx) {\n\treturn luaL_checkudata(L, idx, js_tname).data;\n};\n\nconst pushjs = function(L, v) {\n\tlet b = lua_newuserdata(L);\n\tb.data = v;\n\tluaL_setmetatable(L, js_tname);\n};\n\nconst getmainthread = function(L) {\n\tlua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);\n\tlet mainL = lua_tothread(L, -1);\n\tlua_pop(L, 1);\n\treturn mainL;\n};\n\n/* weak map from states to proxy objects (for each object) in that state */\nconst states = new WeakMap();\n\nconst push = function(L, v) {\n\tswitch (typeof v) {\n\t\tcase \"undefined\":\n\t\t\tlua_pushnil(L);\n\t\t\tbreak;\n\t\tcase \"number\":\n\t\t\tlua_pushnumber(L, v);\n\t\t\tbreak;\n\t\tcase \"string\":\n\t\t\tlua_pushstring(L, to_luastring(v));\n\t\t\tbreak;\n\t\tcase \"boolean\":\n\t\t\tlua_pushboolean(L, v);\n\t\t\tbreak;\n\t\tcase \"symbol\":\n\t\t\tlua_pushlightuserdata(L, v);\n\t\t\tbreak;\n\t\tcase \"function\":\n\t\t\tif (lua_isproxy(v, L)) {\n\t\t\t\tv(L);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t/* fall through */\n\t\tcase \"object\":\n\t\t\tif (v === null) {\n\t\t\t\t/* can't use null in a WeakMap; grab from registry */\n\t\t\t\tif (lua_rawgetp(L, LUA_REGISTRYINDEX, null) !== LUA_TUSERDATA)\n\t\t\t\t\tthrow Error(js_library_not_loaded);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t/* fall through */\n\t\tdefault: {\n\t\t\t/* Try and push same object again */\n\t\t\tlet objects_seen = states.get(getmainthread(L));\n\t\t\tif (!objects_seen) throw Error(js_library_not_loaded);\n\t\t\tlet p = objects_seen.get(v);\n\t\t\tif (p) {\n\t\t\t\tp(L);\n\t\t\t} else {\n\t\t\t\tpushjs(L, v);\n\t\t\t\tp = lua_toproxy(L, -1);\n\t\t\t\tobjects_seen.set(v, p);\n\t\t\t}\n\t\t}\n\t}\n};\n\nconst atnativeerror = function(L) {\n\tlet u = lua_touserdata(L, 1);\n\tpush(L, u);\n\treturn 1;\n};\n\nconst tojs = function(L, idx) {\n\tswitch(lua_type(L, idx)) {\n\t\tcase LUA_TNONE:\n\t\tcase LUA_TNIL:\n\t\t\treturn void 0;\n\t\tcase LUA_TBOOLEAN:\n\t\t\treturn lua_toboolean(L, idx);\n\t\tcase LUA_TLIGHTUSERDATA:\n\t\t\treturn lua_touserdata(L, idx);\n\t\tcase LUA_TNUMBER:\n\t\t\treturn lua_tonumber(L, idx);\n\t\tcase LUA_TSTRING:\n\t\t\treturn lua_tojsstring(L, idx);\n\t\tcase LUA_TUSERDATA: {\n\t\t\tlet u = testjs(L, idx);\n\t\t\tif (u !== void 0)\n\t\t\t\treturn u;\n\t\t}\n\t\t/* fall through */\n\t\tcase LUA_TTABLE:\n\t\tcase LUA_TFUNCTION:\n\t\tcase LUA_TTHREAD:\n\t\t/* fall through */\n\t\tdefault:\n\t\t\treturn wrap(L, lua_toproxy(L, idx));\n\t}\n};\n\n/* Calls function on the stack with `nargs` from the stack.\n On lua error, re-throws as javascript error\n On success, returns single return value */\nconst jscall = function(L, nargs) {\n\tlet status = lua_pcall(L, nargs, 1, 0);\n\tlet r = tojs(L, -1);\n\tlua_pop(L, 1);\n\tswitch(status) {\n\t\tcase LUA_OK:\n\t\t\treturn r;\n\t\tdefault:\n\t\t\tthrow r;\n\t}\n};\n\nconst invoke = function(L, p, thisarg, args, n_results) {\n\tif (!isobject(args)) throw new TypeError(\"`args` argument must be an object\");\n\tlet length = +args.length;\n\tif (!(length >= 0)) length = 0; /* Keep NaN in mind */\n\tluaL_checkstack(L, 2+length, null);\n\tlet base = lua_gettop(L);\n\tp(L);\n\tpush(L, thisarg);\n\tfor (let i=0; ivoid 0;\");\n\tconst raw_arrow_function = function() {\n\t\tlet f = make_arrow_function();\n\t\tdelete f.length;\n\t\tdelete f.name;\n\t\treturn f;\n\t};\n\n\t/*\n\tArrow functions do not have a .prototype field:\n\n\t```js\n\tReflect.ownKeys((() = >void 0)) // Array [ \"length\", \"name\" ]\n\t```\n\n\tHowever they cannot be used as a constructor:\n\n\t```js\n\tnew (new Proxy(() => void 0, { construct: function() { return {}; } })) // TypeError: (intermediate value) is not a constructor\n\tnew (new Proxy(function(){}, { construct: function() { return {}; } })) // {}\n\t```\n\t*/\n\tconst createproxy = function(L1, p, type) {\n\t\tconst L = getmainthread(L1);\n\t\tlet target;\n\t\tswitch (type) {\n\t\t\tcase \"function\":\n\t\t\t\ttarget = raw_function();\n\t\t\t\tbreak;\n\t\t\tcase \"arrow_function\":\n\t\t\t\ttarget = raw_arrow_function();\n\t\t\t\tbreak;\n\t\t\tcase \"object\":\n\t\t\t\ttarget = {};\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow TypeError(\"invalid type to createproxy\");\n\t\t}\n\t\ttarget[p_symbol] = p;\n\t\ttarget[L_symbol] = L;\n\t\treturn new Proxy(target, proxy_handlers);\n\t};\n\n\tconst valid_types = [\"function\", \"arrow_function\", \"object\"];\n\tconst valid_types_as_luastring = valid_types.map((v) => to_luastring(v));\n\tjslib[\"createproxy\"] = function(L) {\n\t\tluaL_checkany(L, 1);\n\t\tlet type = valid_types[luaL_checkoption(L, 2, valid_types_as_luastring[0], valid_types_as_luastring)];\n\t\tlet fengariProxy = createproxy(L, lua_toproxy(L, 1), type);\n\t\tpush(L, fengariProxy);\n\t\treturn 1;\n\t};\n}\n\nlet jsmt = {\n\t\"__index\": function(L) {\n\t\tlet u = checkjs(L, 1);\n\t\tlet k = tojs(L, 2);\n\t\tpush(L, u[k]);\n\t\treturn 1;\n\t},\n\t\"__newindex\": function(L) {\n\t\tlet u = checkjs(L, 1);\n\t\tlet k = tojs(L, 2);\n\t\tlet v = tojs(L, 3);\n\t\tif (v === void 0)\n\t\t\tReflect_deleteProperty(u, k);\n\t\telse\n\t\t\tu[k] = v;\n\t\treturn 0;\n\t},\n\t\"__tostring\": function(L) {\n\t\tlet u = checkjs(L, 1);\n\t\tlet s = toString(u);\n\t\tlua_pushstring(L, to_luastring(s));\n\t\treturn 1;\n\t},\n\t\"__call\": function(L) {\n\t\tlet u = checkjs(L, 1);\n\t\tlet nargs = lua_gettop(L)-1;\n\t\tlet thisarg;\n\t\tlet args = new Array(Math.max(0, nargs-1));\n\t\tif (nargs > 0) {\n\t\t\tthisarg = tojs(L, 2);\n\t\t\tif (nargs-- > 0) {\n\t\t\t\tfor (let i = 0; i < nargs; i++) {\n\t\t\t\t\targs[i] = tojs(L, i+3);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tpush(L, apply(u, thisarg, args));\n\t\treturn 1;\n\t},\n\t\"__pairs\": function(L) {\n\t\tlet u = checkjs(L, 1);\n\t\tlet f;\n\t\tlet iter, state, first;\n\t\tif (typeof Symbol !== \"function\" || (f = u[Symbol.for(\"__pairs\")]) === void 0) {\n\t\t\t/* By default, iterate over Object.keys */\n\t\t\titer = function(last) {\n\t\t\t\tif (this.index >= this.keys.length)\n\t\t\t\t\treturn;\n\t\t\t\tlet key = this.keys[this.index++];\n\t\t\t\treturn [key, this.object[key]];\n\t\t\t};\n\t\t\tstate = {\n\t\t\t\tobject: u,\n\t\t\t\tkeys: Object.keys(u),\n\t\t\t\tindex: 0,\n\t\t\t};\n\t\t} else {\n\t\t\tlet r = apply(f, u, []);\n\t\t\tif (r === void 0)\n\t\t\t\tluaL_error(L, to_luastring(\"bad '__pairs' result (object with keys 'iter', 'state', 'first' expected)\"));\n\t\t\titer = r.iter;\n\t\t\tif (iter === void 0)\n\t\t\t\tluaL_error(L, to_luastring(\"bad '__pairs' result (object.iter is missing)\"));\n\t\t\tstate = r.state;\n\t\t\tfirst = r.first;\n\t\t}\n\t\tlua_pushcfunction(L, function() {\n\t\t\tlet state = tojs(L, 1);\n\t\t\tlet last = tojs(L, 2);\n\t\t\tlet r = apply(iter, state, [last]);\n\t\t\t/* returning undefined indicates end of iteration */\n\t\t\tif (r === void 0)\n\t\t\t\treturn 0;\n\t\t\t/* otherwise it should return an array of results */\n\t\t\tif (!Array.isArray(r))\n\t\t\t\tluaL_error(L, to_luastring(\"bad iterator result (Array or undefined expected)\"));\n\t\t\tluaL_checkstack(L, r.length, null);\n\t\t\tfor (let i=0; i 0) {\n let o = ci.funcOff + idx;\n api_check(L, idx <= ci.top - (ci.funcOff + 1), \"unacceptable index\");\n if (o >= L.top) return lobject.luaO_nilobject;\n else return L.stack[o];\n } else if (idx > LUA_REGISTRYINDEX) {\n api_check(L, idx !== 0 && -idx <= L.top, \"invalid index\");\n return L.stack[L.top + idx];\n } else if (idx === LUA_REGISTRYINDEX) {\n return L.l_G.l_registry;\n } else { /* upvalues */\n idx = LUA_REGISTRYINDEX - idx;\n api_check(L, idx <= lfunc.MAXUPVAL + 1, \"upvalue index too large\");\n if (ci.func.ttislcf()) /* light C function? */\n return lobject.luaO_nilobject; /* it has no upvalues */\n else {\n return idx <= ci.func.value.nupvalues ? ci.func.value.upvalue[idx - 1] : lobject.luaO_nilobject;\n }\n }\n};\n\n// Like index2addr but returns the index on stack; doesn't allow pseudo indices\nconst index2addr_ = function(L, idx) {\n let ci = L.ci;\n if (idx > 0) {\n let o = ci.funcOff + idx;\n api_check(L, idx <= ci.top - (ci.funcOff + 1), \"unacceptable index\");\n if (o >= L.top) return null;\n else return o;\n } else if (idx > LUA_REGISTRYINDEX) {\n api_check(L, idx !== 0 && -idx <= L.top, \"invalid index\");\n return L.top + idx;\n } else { /* registry or upvalue */\n throw Error(\"attempt to use pseudo-index\");\n }\n};\n\nconst lua_checkstack = function(L, n) {\n let res;\n let ci = L.ci;\n api_check(L, n >= 0, \"negative 'n'\");\n if (L.stack_last - L.top > n) /* stack large enough? */\n res = true;\n else { /* no; need to grow stack */\n let inuse = L.top + lstate.EXTRA_STACK;\n if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */\n res = false; /* no */\n else { /* try to grow stack */\n ldo.luaD_growstack(L, n);\n res = true;\n }\n }\n\n if (res && ci.top < L.top + n)\n ci.top = L.top + n; /* adjust frame top */\n\n return res;\n};\n\nconst lua_xmove = function(from, to, n) {\n if (from === to) return;\n api_checknelems(from, n);\n api_check(from, from.l_G === to.l_G, \"moving among independent states\");\n api_check(from, to.ci.top - to.top >= n, \"stack overflow\");\n from.top -= n;\n for (let i = 0; i < n; i++) {\n to.stack[to.top] = new lobject.TValue();\n lobject.setobj2s(to, to.top, from.stack[from.top + i]);\n delete from.stack[from.top + i];\n to.top++;\n }\n};\n\n/*\n** basic stack manipulation\n*/\n\n/*\n** convert an acceptable stack index into an absolute index\n*/\nconst lua_absindex = function(L, idx) {\n return (idx > 0 || idx <= LUA_REGISTRYINDEX)\n ? idx\n : (L.top - L.ci.funcOff) + idx;\n};\n\nconst lua_gettop = function(L) {\n return L.top - (L.ci.funcOff + 1);\n};\n\nconst lua_pushvalue = function(L, idx) {\n lobject.pushobj2s(L, index2addr(L, idx));\n api_check(L, L.top <= L.ci.top, \"stack overflow\");\n};\n\nconst lua_settop = function(L, idx) {\n let func = L.ci.funcOff;\n let newtop;\n if (idx >= 0) {\n api_check(L, idx <= L.stack_last - (func + 1), \"new top too large\");\n newtop = func + 1 + idx;\n } else {\n api_check(L, -(idx + 1) <= L.top - (func + 1), \"invalid new top\");\n newtop = L.top + idx + 1; /* 'subtract' index (index is negative) */\n }\n ldo.adjust_top(L, newtop);\n};\n\nconst lua_pop = function(L, n) {\n lua_settop(L, -n - 1);\n};\n\nconst reverse = function(L, from, to) {\n for (; from < to; from++, to--) {\n let fromtv = L.stack[from];\n let temp = new TValue(fromtv.type, fromtv.value);\n lobject.setobjs2s(L, from, to);\n lobject.setobj2s(L, to, temp);\n }\n};\n\n/*\n** Let x = AB, where A is a prefix of length 'n'. Then,\n** rotate x n === BA. But BA === (A^r . B^r)^r.\n*/\nconst lua_rotate = function(L, idx, n) {\n let t = L.top - 1;\n let pIdx = index2addr_(L, idx);\n let p = L.stack[pIdx];\n api_check(L, isvalid(p) && idx > LUA_REGISTRYINDEX, \"index not in the stack\");\n api_check(L, (n >= 0 ? n : -n) <= (t - pIdx + 1), \"invalid 'n'\");\n let m = n >= 0 ? t - n : pIdx - n - 1; /* end of prefix */\n reverse(L, pIdx, m);\n reverse(L, m + 1, L.top - 1);\n reverse(L, pIdx, L.top - 1);\n};\n\nconst lua_copy = function(L, fromidx, toidx) {\n let from = index2addr(L, fromidx);\n index2addr(L, toidx).setfrom(from);\n};\n\nconst lua_remove = function(L, idx) {\n lua_rotate(L, idx, -1);\n lua_pop(L, 1);\n};\n\nconst lua_insert = function(L, idx) {\n lua_rotate(L, idx, 1);\n};\n\nconst lua_replace = function(L, idx) {\n lua_copy(L, -1, idx);\n lua_pop(L, 1);\n};\n\n/*\n** push functions (JS -> stack)\n*/\n\nconst lua_pushnil = function(L) {\n L.stack[L.top] = new TValue(LUA_TNIL, null);\n api_incr_top(L);\n};\n\nconst lua_pushnumber = function(L, n) {\n fengari_argcheck(typeof n === \"number\");\n L.stack[L.top] = new TValue(LUA_TNUMFLT, n);\n api_incr_top(L);\n};\n\nconst lua_pushinteger = function(L, n) {\n fengari_argcheckinteger(n);\n L.stack[L.top] = new TValue(LUA_TNUMINT, n);\n api_incr_top(L);\n};\n\nconst lua_pushlstring = function(L, s, len) {\n fengari_argcheckinteger(len);\n let ts;\n if (len === 0) {\n s = to_luastring(\"\", true);\n ts = luaS_bless(L, s);\n } else {\n s = from_userstring(s);\n api_check(L, s.length >= len, \"invalid length to lua_pushlstring\");\n ts = luaS_new(L, s.subarray(0, len));\n }\n lobject.pushsvalue2s(L, ts);\n api_check(L, L.top <= L.ci.top, \"stack overflow\");\n return ts.value;\n};\n\nconst lua_pushstring = function (L, s) {\n if (s === undefined || s === null) {\n L.stack[L.top] = new TValue(LUA_TNIL, null);\n L.top++;\n } else {\n let ts = luaS_new(L, from_userstring(s));\n lobject.pushsvalue2s(L, ts);\n s = ts.getstr(); /* internal copy */\n }\n api_check(L, L.top <= L.ci.top, \"stack overflow\");\n return s;\n};\n\nconst lua_pushvfstring = function (L, fmt, argp) {\n fmt = from_userstring(fmt);\n return lobject.luaO_pushvfstring(L, fmt, argp);\n};\n\nconst lua_pushfstring = function (L, fmt, ...argp) {\n fmt = from_userstring(fmt);\n return lobject.luaO_pushvfstring(L, fmt, argp);\n};\n\n/* Similar to lua_pushstring, but takes a JS string */\nconst lua_pushliteral = function (L, s) {\n if (s === undefined || s === null) {\n L.stack[L.top] = new TValue(LUA_TNIL, null);\n L.top++;\n } else {\n fengari_argcheck(typeof s === \"string\");\n let ts = luaS_newliteral(L, s);\n lobject.pushsvalue2s(L, ts);\n s = ts.getstr(); /* internal copy */\n }\n api_check(L, L.top <= L.ci.top, \"stack overflow\");\n\n return s;\n};\n\nconst lua_pushcclosure = function(L, fn, n) {\n fengari_argcheck(typeof fn === \"function\");\n fengari_argcheckinteger(n);\n if (n === 0)\n L.stack[L.top] = new TValue(LUA_TLCF, fn);\n else {\n api_checknelems(L, n);\n api_check(L, n <= lfunc.MAXUPVAL, \"upvalue index too large\");\n let cl = new CClosure(L, fn, n);\n for (let i=0; i0)\n --L.top;\n L.stack[L.top].setclCvalue(cl);\n }\n api_incr_top(L);\n};\n\nconst lua_pushjsclosure = lua_pushcclosure;\n\nconst lua_pushcfunction = function(L, fn) {\n lua_pushcclosure(L, fn, 0);\n};\n\nconst lua_pushjsfunction = lua_pushcfunction;\n\nconst lua_pushboolean = function(L, b) {\n L.stack[L.top] = new TValue(LUA_TBOOLEAN, !!b);\n api_incr_top(L);\n};\n\nconst lua_pushlightuserdata = function(L, p) {\n L.stack[L.top] = new TValue(LUA_TLIGHTUSERDATA, p);\n api_incr_top(L);\n};\n\nconst lua_pushthread = function(L) {\n L.stack[L.top] = new TValue(LUA_TTHREAD, L);\n api_incr_top(L);\n return L.l_G.mainthread === L;\n};\n\nconst lua_pushglobaltable = function(L) {\n lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);\n};\n\n/*\n** set functions (stack -> Lua)\n*/\n\n/*\n** t[k] = value at the top of the stack (where 'k' is a string)\n*/\nconst auxsetstr = function(L, t, k) {\n let str = luaS_new(L, from_userstring(k));\n api_checknelems(L, 1);\n lobject.pushsvalue2s(L, str); /* push 'str' (to make it a TValue) */\n api_check(L, L.top <= L.ci.top, \"stack overflow\");\n lvm.settable(L, t, L.stack[L.top - 1], L.stack[L.top - 2]);\n /* pop value and key */\n delete L.stack[--L.top];\n delete L.stack[--L.top];\n};\n\nconst lua_setglobal = function(L, name) {\n auxsetstr(L, ltable.luaH_getint(L.l_G.l_registry.value, LUA_RIDX_GLOBALS), name);\n};\n\nconst lua_setmetatable = function(L, objindex) {\n api_checknelems(L, 1);\n let mt;\n let obj = index2addr(L, objindex);\n if (L.stack[L.top - 1].ttisnil())\n mt = null;\n else {\n api_check(L, L.stack[L.top - 1].ttistable(), \"table expected\");\n mt = L.stack[L.top - 1].value;\n }\n\n switch (obj.ttnov()) {\n case LUA_TUSERDATA:\n case LUA_TTABLE: {\n obj.value.metatable = mt;\n break;\n }\n default: {\n L.l_G.mt[obj.ttnov()] = mt;\n break;\n }\n }\n\n delete L.stack[--L.top];\n return true;\n};\n\nconst lua_settable = function(L, idx) {\n api_checknelems(L, 2);\n let t = index2addr(L, idx);\n lvm.settable(L, t, L.stack[L.top - 2], L.stack[L.top - 1]);\n delete L.stack[--L.top];\n delete L.stack[--L.top];\n};\n\nconst lua_setfield = function(L, idx, k) {\n auxsetstr(L, index2addr(L, idx), k);\n};\n\nconst lua_seti = function(L, idx, n) {\n fengari_argcheckinteger(n);\n api_checknelems(L, 1);\n let t = index2addr(L, idx);\n L.stack[L.top] = new TValue(LUA_TNUMINT, n);\n api_incr_top(L);\n lvm.settable(L, t, L.stack[L.top - 1], L.stack[L.top - 2]);\n /* pop value and key */\n delete L.stack[--L.top];\n delete L.stack[--L.top];\n};\n\nconst lua_rawset = function(L, idx) {\n api_checknelems(L, 2);\n let o = index2addr(L, idx);\n api_check(L, o.ttistable(), \"table expected\");\n let k = L.stack[L.top - 2];\n let v = L.stack[L.top - 1];\n ltable.luaH_setfrom(L, o.value, k, v);\n ltable.invalidateTMcache(o.value);\n delete L.stack[--L.top];\n delete L.stack[--L.top];\n};\n\nconst lua_rawseti = function(L, idx, n) {\n fengari_argcheckinteger(n);\n api_checknelems(L, 1);\n let o = index2addr(L, idx);\n api_check(L, o.ttistable(), \"table expected\");\n ltable.luaH_setint(o.value, n, L.stack[L.top - 1]);\n delete L.stack[--L.top];\n};\n\nconst lua_rawsetp = function(L, idx, p) {\n api_checknelems(L, 1);\n let o = index2addr(L, idx);\n api_check(L, o.ttistable(), \"table expected\");\n let k = new TValue(LUA_TLIGHTUSERDATA, p);\n let v = L.stack[L.top - 1];\n ltable.luaH_setfrom(L, o.value, k, v);\n delete L.stack[--L.top];\n};\n\n/*\n** get functions (Lua -> stack)\n*/\n\nconst auxgetstr = function(L, t, k) {\n let str = luaS_new(L, from_userstring(k));\n lobject.pushsvalue2s(L, str);\n api_check(L, L.top <= L.ci.top, \"stack overflow\");\n lvm.luaV_gettable(L, t, L.stack[L.top - 1], L.top - 1);\n return L.stack[L.top - 1].ttnov();\n};\n\nconst lua_rawgeti = function(L, idx, n) {\n let t = index2addr(L, idx);\n fengari_argcheckinteger(n);\n api_check(L, t.ttistable(), \"table expected\");\n lobject.pushobj2s(L, ltable.luaH_getint(t.value, n));\n api_check(L, L.top <= L.ci.top, \"stack overflow\");\n return L.stack[L.top - 1].ttnov();\n};\n\nconst lua_rawgetp = function(L, idx, p) {\n let t = index2addr(L, idx);\n api_check(L, t.ttistable(), \"table expected\");\n let k = new TValue(LUA_TLIGHTUSERDATA, p);\n lobject.pushobj2s(L, ltable.luaH_get(L, t.value, k));\n api_check(L, L.top <= L.ci.top, \"stack overflow\");\n return L.stack[L.top - 1].ttnov();\n};\n\nconst lua_rawget = function(L, idx) {\n let t = index2addr(L, idx);\n api_check(L, t.ttistable(t), \"table expected\");\n lobject.setobj2s(L, L.top - 1, ltable.luaH_get(L, t.value, L.stack[L.top - 1]));\n return L.stack[L.top - 1].ttnov();\n};\n\n// narray and nrec are mostly useless for this implementation\nconst lua_createtable = function(L, narray, nrec) {\n let t = new lobject.TValue(LUA_TTABLE, ltable.luaH_new(L));\n L.stack[L.top] = t;\n api_incr_top(L);\n};\n\nconst luaS_newudata = function(L, size) {\n return new lobject.Udata(L, size);\n};\n\nconst lua_newuserdata = function(L, size) {\n let u = luaS_newudata(L, size);\n L.stack[L.top] = new lobject.TValue(LUA_TUSERDATA, u);\n api_incr_top(L);\n return u.data;\n};\n\nconst aux_upvalue = function(L, fi, n) {\n fengari_argcheckinteger(n);\n switch(fi.ttype()) {\n case LUA_TCCL: { /* C closure */\n let f = fi.value;\n if (!(1 <= n && n <= f.nupvalues)) return null;\n return {\n name: to_luastring(\"\", true),\n val: f.upvalue[n-1]\n };\n }\n case LUA_TLCL: { /* Lua closure */\n let f = fi.value;\n let p = f.p;\n if (!(1 <= n && n <= p.upvalues.length)) return null;\n let name = p.upvalues[n-1].name;\n return {\n name: name ? name.getstr() : to_luastring(\"(*no name)\", true),\n val: f.upvals[n-1]\n };\n }\n default: return null; /* not a closure */\n }\n};\n\nconst lua_getupvalue = function(L, funcindex, n) {\n let up = aux_upvalue(L, index2addr(L, funcindex), n);\n if (up) {\n let name = up.name;\n let val = up.val;\n lobject.pushobj2s(L, val);\n api_check(L, L.top <= L.ci.top, \"stack overflow\");\n return name;\n }\n return null;\n};\n\nconst lua_setupvalue = function(L, funcindex, n) {\n let fi = index2addr(L, funcindex);\n api_checknelems(L, 1);\n let aux = aux_upvalue(L, fi, n);\n if (aux) {\n let name = aux.name;\n let val = aux.val;\n val.setfrom(L.stack[L.top-1]);\n delete L.stack[--L.top];\n return name;\n }\n return null;\n};\n\nconst lua_newtable = function(L) {\n lua_createtable(L, 0, 0);\n};\n\nconst lua_register = function(L, n, f) {\n lua_pushcfunction(L, f);\n lua_setglobal(L, n);\n};\n\nconst lua_getmetatable = function(L, objindex) {\n let obj = index2addr(L, objindex);\n let mt;\n let res = false;\n switch (obj.ttnov()) {\n case LUA_TTABLE:\n case LUA_TUSERDATA:\n mt = obj.value.metatable;\n break;\n default:\n mt = L.l_G.mt[obj.ttnov()];\n break;\n }\n\n if (mt !== null && mt !== undefined) {\n L.stack[L.top] = new TValue(LUA_TTABLE, mt);\n api_incr_top(L);\n res = true;\n }\n\n return res;\n};\n\nconst lua_getuservalue = function(L, idx) {\n let o = index2addr(L, idx);\n api_check(L, o.ttisfulluserdata(), \"full userdata expected\");\n let uv = o.value.uservalue;\n L.stack[L.top] = new TValue(uv.type, uv.value);\n api_incr_top(L);\n return L.stack[L.top - 1].ttnov();\n};\n\nconst lua_gettable = function(L, idx) {\n let t = index2addr(L, idx);\n lvm.luaV_gettable(L, t, L.stack[L.top - 1], L.top - 1);\n return L.stack[L.top - 1].ttnov();\n};\n\nconst lua_getfield = function(L, idx, k) {\n return auxgetstr(L, index2addr(L, idx), k);\n};\n\nconst lua_geti = function(L, idx, n) {\n let t = index2addr(L, idx);\n fengari_argcheckinteger(n);\n L.stack[L.top] = new TValue(LUA_TNUMINT, n);\n api_incr_top(L);\n lvm.luaV_gettable(L, t, L.stack[L.top - 1], L.top - 1);\n return L.stack[L.top - 1].ttnov();\n};\n\nconst lua_getglobal = function(L, name) {\n return auxgetstr(L, ltable.luaH_getint(L.l_G.l_registry.value, LUA_RIDX_GLOBALS), name);\n};\n\n/*\n** access functions (stack -> JS)\n*/\n\nconst lua_toboolean = function(L, idx) {\n let o = index2addr(L, idx);\n return !o.l_isfalse();\n};\n\nconst lua_tolstring = function(L, idx) {\n let o = index2addr(L, idx);\n\n if (!o.ttisstring()) {\n if (!lvm.cvt2str(o)) { /* not convertible? */\n return null;\n }\n lobject.luaO_tostring(L, o);\n }\n return o.svalue();\n};\n\nconst lua_tostring = lua_tolstring;\n\nconst lua_tojsstring = function(L, idx) {\n let o = index2addr(L, idx);\n\n if (!o.ttisstring()) {\n if (!lvm.cvt2str(o)) { /* not convertible? */\n return null;\n }\n lobject.luaO_tostring(L, o);\n }\n return o.jsstring();\n};\n\nconst lua_todataview = function(L, idx) {\n let u8 = lua_tolstring(L, idx);\n return new DataView(u8.buffer, u8.byteOffset, u8.byteLength);\n};\n\nconst lua_rawlen = function(L, idx) {\n let o = index2addr(L, idx);\n switch (o.ttype()) {\n case LUA_TSHRSTR:\n case LUA_TLNGSTR:\n return o.vslen();\n case LUA_TUSERDATA:\n return o.value.len;\n case LUA_TTABLE:\n return ltable.luaH_getn(o.value);\n default:\n return 0;\n }\n};\n\nconst lua_tocfunction = function(L, idx) {\n let o = index2addr(L, idx);\n if (o.ttislcf() || o.ttisCclosure()) return o.value;\n else return null; /* not a C function */\n};\n\nconst lua_tointeger = function(L, idx) {\n let n = lua_tointegerx(L, idx);\n return n === false ? 0 : n;\n};\n\nconst lua_tointegerx = function(L, idx) {\n return lvm.tointeger(index2addr(L, idx));\n};\n\nconst lua_tonumber = function(L, idx) {\n let n = lua_tonumberx(L, idx);\n return n === false ? 0 : n;\n};\n\nconst lua_tonumberx = function(L, idx) {\n return lvm.tonumber(index2addr(L, idx));\n};\n\nconst lua_touserdata = function(L, idx) {\n let o = index2addr(L, idx);\n switch (o.ttnov()) {\n case LUA_TUSERDATA:\n return o.value.data;\n case LUA_TLIGHTUSERDATA:\n return o.value;\n default: return null;\n }\n};\n\nconst lua_tothread = function(L, idx) {\n let o = index2addr(L, idx);\n return o.ttisthread() ? o.value : null;\n};\n\nconst lua_topointer = function(L, idx) {\n let o = index2addr(L, idx);\n switch (o.ttype()) {\n case LUA_TTABLE:\n case LUA_TLCL:\n case LUA_TCCL:\n case LUA_TLCF:\n case LUA_TTHREAD:\n case LUA_TUSERDATA: /* note: this differs in behaviour to reference lua implementation */\n case LUA_TLIGHTUSERDATA:\n return o.value;\n default:\n return null;\n }\n};\n\n\n/* A proxy is a function that the same lua value to the given lua state. */\n\n/* Having a weakmap of created proxies was only way I could think of to provide an 'isproxy' function */\nconst seen = new WeakMap();\n\n/* is the passed object a proxy? is it from the given state? (if passed) */\nconst lua_isproxy = function(p, L) {\n let G = seen.get(p);\n if (!G)\n return false;\n return (L === null) || (L.l_G === G);\n};\n\n/* Use 'create_proxy' helper function so that 'L' is not in scope */\nconst create_proxy = function(G, type, value) {\n let proxy = function(L) {\n api_check(L, L instanceof lstate.lua_State && G === L.l_G, \"must be from same global state\");\n L.stack[L.top] = new TValue(type, value);\n api_incr_top(L);\n };\n seen.set(proxy, G);\n return proxy;\n};\n\nconst lua_toproxy = function(L, idx) {\n let tv = index2addr(L, idx);\n /* pass broken down tv incase it is an upvalue index */\n return create_proxy(L.l_G, tv.type, tv.value);\n};\n\n\nconst lua_compare = function(L, index1, index2, op) {\n let o1 = index2addr(L, index1);\n let o2 = index2addr(L, index2);\n\n let i = 0;\n\n if (isvalid(o1) && isvalid(o2)) {\n switch (op) {\n case LUA_OPEQ: i = lvm.luaV_equalobj(L, o1, o2); break;\n case LUA_OPLT: i = lvm.luaV_lessthan(L, o1, o2); break;\n case LUA_OPLE: i = lvm.luaV_lessequal(L, o1, o2); break;\n default: api_check(L, false, \"invalid option\");\n }\n }\n\n return i;\n};\n\nconst lua_stringtonumber = function(L, s) {\n let tv = new TValue();\n let sz = lobject.luaO_str2num(s, tv);\n if (sz !== 0) {\n L.stack[L.top] = tv;\n api_incr_top(L);\n }\n return sz;\n};\n\nconst f_call = function(L, ud) {\n ldo.luaD_callnoyield(L, ud.funcOff, ud.nresults);\n};\n\nconst lua_type = function(L, idx) {\n let o = index2addr(L, idx);\n return isvalid(o) ? o.ttnov() : LUA_TNONE;\n};\n\nconst lua_typename = function(L, t) {\n api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, \"invalid tag\");\n return ltm.ttypename(t);\n};\n\nconst lua_iscfunction = function(L, idx) {\n let o = index2addr(L, idx);\n return o.ttislcf(o) || o.ttisCclosure();\n};\n\nconst lua_isnil = function(L, n) {\n return lua_type(L, n) === LUA_TNIL;\n};\n\nconst lua_isboolean = function(L, n) {\n return lua_type(L, n) === LUA_TBOOLEAN;\n};\n\nconst lua_isnone = function(L, n) {\n return lua_type(L, n) === LUA_TNONE;\n};\n\nconst lua_isnoneornil = function(L, n) {\n return lua_type(L, n) <= 0;\n};\n\nconst lua_istable = function(L, idx) {\n return index2addr(L, idx).ttistable();\n};\n\nconst lua_isinteger = function(L, idx) {\n return index2addr(L, idx).ttisinteger();\n};\n\nconst lua_isnumber = function(L, idx) {\n return lvm.tonumber(index2addr(L, idx)) !== false;\n};\n\nconst lua_isstring = function(L, idx) {\n let o = index2addr(L, idx);\n return o.ttisstring() || lvm.cvt2str(o);\n};\n\nconst lua_isuserdata = function(L, idx) {\n let o = index2addr(L, idx);\n return o.ttisfulluserdata(o) || o.ttislightuserdata();\n};\n\nconst lua_isthread = function(L, idx) {\n return lua_type(L, idx) === LUA_TTHREAD;\n};\n\nconst lua_isfunction = function(L, idx) {\n return lua_type(L, idx) === LUA_TFUNCTION;\n};\n\nconst lua_islightuserdata = function(L, idx) {\n return lua_type(L, idx) === LUA_TLIGHTUSERDATA;\n};\n\nconst lua_rawequal = function(L, index1, index2) {\n let o1 = index2addr(L, index1);\n let o2 = index2addr(L, index2);\n return isvalid(o1) && isvalid(o2) ? lvm.luaV_equalobj(null, o1, o2) : 0;\n};\n\nconst lua_arith = function(L, op) {\n if (op !== LUA_OPUNM && op !== LUA_OPBNOT)\n api_checknelems(L, 2); /* all other operations expect two operands */\n else { /* for unary operations, add fake 2nd operand */\n api_checknelems(L, 1);\n lobject.pushobj2s(L, L.stack[L.top-1]);\n api_check(L, L.top <= L.ci.top, \"stack overflow\");\n }\n /* first operand at top - 2, second at top - 1; result go to top - 2 */\n lobject.luaO_arith(L, op, L.stack[L.top - 2], L.stack[L.top - 1], L.stack[L.top - 2]);\n delete L.stack[--L.top]; /* remove second operand */\n};\n\n/*\n** 'load' and 'call' functions (run Lua code)\n*/\n\nconst default_chunkname = to_luastring(\"?\");\nconst lua_load = function(L, reader, data, chunkname, mode) {\n if (!chunkname) chunkname = default_chunkname;\n else chunkname = from_userstring(chunkname);\n if (mode !== null) mode = from_userstring(mode);\n let z = new ZIO(L, reader, data);\n let status = ldo.luaD_protectedparser(L, z, chunkname, mode);\n if (status === LUA_OK) { /* no errors? */\n let f = L.stack[L.top - 1].value; /* get newly created function */\n if (f.nupvalues >= 1) { /* does it have an upvalue? */\n /* get global table from registry */\n let gt = ltable.luaH_getint(L.l_G.l_registry.value, LUA_RIDX_GLOBALS);\n /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */\n f.upvals[0].setfrom(gt);\n }\n }\n return status;\n};\n\nconst lua_dump = function(L, writer, data, strip) {\n api_checknelems(L, 1);\n let o = L.stack[L.top -1];\n if (o.ttisLclosure())\n return luaU_dump(L, o.value.p, writer, data, strip);\n return 1;\n};\n\nconst lua_status = function(L) {\n return L.status;\n};\n\nconst lua_setuservalue = function(L, idx) {\n api_checknelems(L, 1);\n let o = index2addr(L, idx);\n api_check(L, o.ttisfulluserdata(), \"full userdata expected\");\n o.value.uservalue.setfrom(L.stack[L.top - 1]);\n delete L.stack[--L.top];\n};\n\nconst checkresults = function(L,na,nr) {\n api_check(L, nr === LUA_MULTRET || (L.ci.top - L.top >= (nr) - (na)),\n \"results from function overflow current stack size\");\n};\n\nconst lua_callk = function(L, nargs, nresults, ctx, k) {\n api_check(L, k === null || !(L.ci.callstatus & lstate.CIST_LUA), \"cannot use continuations inside hooks\");\n api_checknelems(L, nargs + 1);\n api_check(L, L.status === LUA_OK, \"cannot do calls on non-normal thread\");\n checkresults(L, nargs, nresults);\n let func = L.top - (nargs + 1);\n if (k !== null && L.nny === 0) { /* need to prepare continuation? */\n L.ci.c_k = k;\n L.ci.c_ctx = ctx;\n ldo.luaD_call(L, func, nresults);\n } else { /* no continuation or no yieldable */\n ldo.luaD_callnoyield(L, func, nresults);\n }\n\n if (nresults === LUA_MULTRET && L.ci.top < L.top)\n L.ci.top = L.top;\n};\n\nconst lua_call = function(L, n, r) {\n lua_callk(L, n, r, 0, null);\n};\n\nconst lua_pcallk = function(L, nargs, nresults, errfunc, ctx, k) {\n api_check(L, k === null || !(L.ci.callstatus & lstate.CIST_LUA), \"cannot use continuations inside hooks\");\n api_checknelems(L, nargs + 1);\n api_check(L, L.status === LUA_OK, \"cannot do calls on non-normal thread\");\n checkresults(L, nargs, nresults);\n let status;\n let func;\n if (errfunc === 0)\n func = 0;\n else {\n func = index2addr_(L, errfunc);\n }\n let funcOff = L.top - (nargs + 1); /* function to be called */\n if (k === null || L.nny > 0) { /* no continuation or no yieldable? */\n let c = {\n funcOff: funcOff,\n nresults: nresults /* do a 'conventional' protected call */\n };\n status = ldo.luaD_pcall(L, f_call, c, funcOff, func);\n } else { /* prepare continuation (call is already protected by 'resume') */\n let ci = L.ci;\n ci.c_k = k; /* prepare continuation (call is already protected by 'resume') */\n ci.c_ctx = ctx; /* prepare continuation (call is already protected by 'resume') */\n /* save information for error recovery */\n ci.extra = funcOff;\n ci.c_old_errfunc = L.errfunc;\n L.errfunc = func;\n ci.callstatus &= ~lstate.CIST_OAH | L.allowhook;\n ci.callstatus |= lstate.CIST_YPCALL; /* function can do error recovery */\n ldo.luaD_call(L, funcOff, nresults); /* do the call */\n ci.callstatus &= ~lstate.CIST_YPCALL;\n L.errfunc = ci.c_old_errfunc;\n status = LUA_OK;\n }\n\n if (nresults === LUA_MULTRET && L.ci.top < L.top)\n L.ci.top = L.top;\n\n return status;\n};\n\nconst lua_pcall = function(L, n, r, f) {\n return lua_pcallk(L, n, r, f, 0, null);\n};\n\n/*\n** miscellaneous functions\n*/\n\nconst lua_error = function(L) {\n api_checknelems(L, 1);\n ldebug.luaG_errormsg(L);\n};\n\nconst lua_next = function(L, idx) {\n let t = index2addr(L, idx);\n api_check(L, t.ttistable(), \"table expected\");\n L.stack[L.top] = new TValue();\n let more = ltable.luaH_next(L, t.value, L.top - 1);\n if (more) {\n api_incr_top(L);\n return 1;\n } else {\n delete L.stack[L.top];\n delete L.stack[--L.top];\n return 0;\n }\n};\n\nconst lua_concat = function(L, n) {\n api_checknelems(L, n);\n if (n >= 2)\n lvm.luaV_concat(L, n);\n else if (n === 0) {\n lobject.pushsvalue2s(L, luaS_bless(L, to_luastring(\"\", true)));\n api_check(L, L.top <= L.ci.top, \"stack overflow\");\n }\n};\n\nconst lua_len = function(L, idx) {\n let t = index2addr(L, idx);\n let tv = new TValue();\n lvm.luaV_objlen(L, tv, t);\n L.stack[L.top] = tv;\n api_incr_top(L);\n};\n\nconst getupvalref = function(L, fidx, n) {\n let fi = index2addr(L, fidx);\n api_check(L, fi.ttisLclosure(), \"Lua function expected\");\n let f = fi.value;\n fengari_argcheckinteger(n);\n api_check(L, 1 <= n && n <= f.p.upvalues.length, \"invalid upvalue index\");\n return {\n f: f,\n i: n - 1\n };\n};\n\nconst lua_upvalueid = function(L, fidx, n) {\n let fi = index2addr(L, fidx);\n switch (fi.ttype()) {\n case LUA_TLCL: { /* lua closure */\n let ref = getupvalref(L, fidx, n);\n return ref.f.upvals[ref.i];\n }\n case LUA_TCCL: { /* C closure */\n let f = fi.value;\n api_check(L, (n|0) === n && n > 0 && n <= f.nupvalues, \"invalid upvalue index\");\n return f.upvalue[n - 1];\n }\n default: {\n api_check(L, false, \"closure expected\");\n return null;\n }\n }\n};\n\nconst lua_upvaluejoin = function(L, fidx1, n1, fidx2, n2) {\n let ref1 = getupvalref(L, fidx1, n1);\n let ref2 = getupvalref(L, fidx2, n2);\n let up2 = ref2.f.upvals[ref2.i];\n ref1.f.upvals[ref1.i] = up2;\n};\n\n// This functions are only there for compatibility purposes\nconst lua_gc = function () {};\n\nconst lua_getallocf = function () {\n console.warn(\"lua_getallocf is not available\");\n return 0;\n};\n\nconst lua_setallocf = function () {\n console.warn(\"lua_setallocf is not available\");\n return 0;\n};\n\nconst lua_getextraspace = function () {\n console.warn(\"lua_getextraspace is not available\");\n return 0;\n};\n\nmodule.exports.api_incr_top = api_incr_top;\nmodule.exports.api_checknelems = api_checknelems;\nmodule.exports.lua_absindex = lua_absindex;\nmodule.exports.lua_arith = lua_arith;\nmodule.exports.lua_atpanic = lua_atpanic;\nmodule.exports.lua_atnativeerror = lua_atnativeerror;\nmodule.exports.lua_call = lua_call;\nmodule.exports.lua_callk = lua_callk;\nmodule.exports.lua_checkstack = lua_checkstack;\nmodule.exports.lua_compare = lua_compare;\nmodule.exports.lua_concat = lua_concat;\nmodule.exports.lua_copy = lua_copy;\nmodule.exports.lua_createtable = lua_createtable;\nmodule.exports.lua_dump = lua_dump;\nmodule.exports.lua_error = lua_error;\nmodule.exports.lua_gc = lua_gc;\nmodule.exports.lua_getallocf = lua_getallocf;\nmodule.exports.lua_getextraspace = lua_getextraspace;\nmodule.exports.lua_getfield = lua_getfield;\nmodule.exports.lua_getglobal = lua_getglobal;\nmodule.exports.lua_geti = lua_geti;\nmodule.exports.lua_getmetatable = lua_getmetatable;\nmodule.exports.lua_gettable = lua_gettable;\nmodule.exports.lua_gettop = lua_gettop;\nmodule.exports.lua_getupvalue = lua_getupvalue;\nmodule.exports.lua_getuservalue = lua_getuservalue;\nmodule.exports.lua_insert = lua_insert;\nmodule.exports.lua_isboolean = lua_isboolean;\nmodule.exports.lua_iscfunction = lua_iscfunction;\nmodule.exports.lua_isfunction = lua_isfunction;\nmodule.exports.lua_isinteger = lua_isinteger;\nmodule.exports.lua_islightuserdata = lua_islightuserdata;\nmodule.exports.lua_isnil = lua_isnil;\nmodule.exports.lua_isnone = lua_isnone;\nmodule.exports.lua_isnoneornil = lua_isnoneornil;\nmodule.exports.lua_isnumber = lua_isnumber;\nmodule.exports.lua_isproxy = lua_isproxy;\nmodule.exports.lua_isstring = lua_isstring;\nmodule.exports.lua_istable = lua_istable;\nmodule.exports.lua_isthread = lua_isthread;\nmodule.exports.lua_isuserdata = lua_isuserdata;\nmodule.exports.lua_len = lua_len;\nmodule.exports.lua_load = lua_load;\nmodule.exports.lua_newtable = lua_newtable;\nmodule.exports.lua_newuserdata = lua_newuserdata;\nmodule.exports.lua_next = lua_next;\nmodule.exports.lua_pcall = lua_pcall;\nmodule.exports.lua_pcallk = lua_pcallk;\nmodule.exports.lua_pop = lua_pop;\nmodule.exports.lua_pushboolean = lua_pushboolean;\nmodule.exports.lua_pushcclosure = lua_pushcclosure;\nmodule.exports.lua_pushcfunction = lua_pushcfunction;\nmodule.exports.lua_pushfstring = lua_pushfstring;\nmodule.exports.lua_pushglobaltable = lua_pushglobaltable;\nmodule.exports.lua_pushinteger = lua_pushinteger;\nmodule.exports.lua_pushjsclosure = lua_pushjsclosure;\nmodule.exports.lua_pushjsfunction = lua_pushjsfunction;\nmodule.exports.lua_pushlightuserdata = lua_pushlightuserdata;\nmodule.exports.lua_pushliteral = lua_pushliteral;\nmodule.exports.lua_pushlstring = lua_pushlstring;\nmodule.exports.lua_pushnil = lua_pushnil;\nmodule.exports.lua_pushnumber = lua_pushnumber;\nmodule.exports.lua_pushstring = lua_pushstring;\nmodule.exports.lua_pushthread = lua_pushthread;\nmodule.exports.lua_pushvalue = lua_pushvalue;\nmodule.exports.lua_pushvfstring = lua_pushvfstring;\nmodule.exports.lua_rawequal = lua_rawequal;\nmodule.exports.lua_rawget = lua_rawget;\nmodule.exports.lua_rawgeti = lua_rawgeti;\nmodule.exports.lua_rawgetp = lua_rawgetp;\nmodule.exports.lua_rawlen = lua_rawlen;\nmodule.exports.lua_rawset = lua_rawset;\nmodule.exports.lua_rawseti = lua_rawseti;\nmodule.exports.lua_rawsetp = lua_rawsetp;\nmodule.exports.lua_register = lua_register;\nmodule.exports.lua_remove = lua_remove;\nmodule.exports.lua_replace = lua_replace;\nmodule.exports.lua_rotate = lua_rotate;\nmodule.exports.lua_setallocf = lua_setallocf;\nmodule.exports.lua_setfield = lua_setfield;\nmodule.exports.lua_setglobal = lua_setglobal;\nmodule.exports.lua_seti = lua_seti;\nmodule.exports.lua_setmetatable = lua_setmetatable;\nmodule.exports.lua_settable = lua_settable;\nmodule.exports.lua_settop = lua_settop;\nmodule.exports.lua_setupvalue = lua_setupvalue;\nmodule.exports.lua_setuservalue = lua_setuservalue;\nmodule.exports.lua_status = lua_status;\nmodule.exports.lua_stringtonumber = lua_stringtonumber;\nmodule.exports.lua_toboolean = lua_toboolean;\nmodule.exports.lua_tocfunction = lua_tocfunction;\nmodule.exports.lua_todataview = lua_todataview;\nmodule.exports.lua_tointeger = lua_tointeger;\nmodule.exports.lua_tointegerx = lua_tointegerx;\nmodule.exports.lua_tojsstring = lua_tojsstring;\nmodule.exports.lua_tolstring = lua_tolstring;\nmodule.exports.lua_tonumber = lua_tonumber;\nmodule.exports.lua_tonumberx = lua_tonumberx;\nmodule.exports.lua_topointer = lua_topointer;\nmodule.exports.lua_toproxy = lua_toproxy;\nmodule.exports.lua_tostring = lua_tostring;\nmodule.exports.lua_tothread = lua_tothread;\nmodule.exports.lua_touserdata = lua_touserdata;\nmodule.exports.lua_type = lua_type;\nmodule.exports.lua_typename = lua_typename;\nmodule.exports.lua_upvalueid = lua_upvalueid;\nmodule.exports.lua_upvaluejoin = lua_upvaluejoin;\nmodule.exports.lua_version = lua_version;\nmodule.exports.lua_xmove = lua_xmove;\n","\"use strict\";\n\nconst { lua_assert } = require(\"./llimits.js\");\n\nclass MBuffer {\n constructor() {\n this.buffer = null;\n this.n = 0;\n }\n}\n\nconst luaZ_buffer = function(buff) {\n return buff.buffer.subarray(0, buff.n);\n};\n\nconst luaZ_buffremove = function(buff, i) {\n buff.n -= i;\n};\n\nconst luaZ_resetbuffer = function(buff) {\n buff.n = 0;\n};\n\nconst luaZ_resizebuffer = function(L, buff, size) {\n let newbuff = new Uint8Array(size);\n if (buff.buffer)\n newbuff.set(buff.buffer);\n buff.buffer = newbuff;\n};\n\nclass ZIO {\n constructor(L, reader, data) {\n this.L = L; /* Lua state (for reader) */\n lua_assert(typeof reader == \"function\", \"ZIO requires a reader\");\n this.reader = reader; /* reader function */\n this.data = data; /* additional data */\n this.n = 0; /* bytes still unread */\n this.buffer = null;\n this.off = 0; /* current position in buffer */\n }\n\n zgetc () {\n return ((this.n--) > 0) ? this.buffer[this.off++] : luaZ_fill(this);\n }\n}\n\nconst EOZ = -1;\n\nconst luaZ_fill = function(z) {\n let buff = z.reader(z.L, z.data);\n if (buff === null)\n return EOZ;\n lua_assert(buff instanceof Uint8Array, \"Should only load binary of array of bytes\");\n let size = buff.length;\n if (size === 0)\n return EOZ;\n z.buffer = buff;\n z.off = 0;\n z.n = size - 1;\n return z.buffer[z.off++];\n};\n\n/* b should be an array-like that will be set to bytes\n * b_offset is the offset at which to start filling */\nconst luaZ_read = function(z, b, b_offset, n) {\n while (n) {\n if (z.n === 0) { /* no bytes in buffer? */\n if (luaZ_fill(z) === EOZ)\n return n; /* no more input; return number of missing bytes */\n else {\n z.n++; /* luaZ_fill consumed first byte; put it back */\n z.off--;\n }\n }\n let m = (n <= z.n) ? n : z.n; /* min. between n and z->n */\n for (let i=0; i=\", \"<=\", \"~=\",\n \"<<\", \">>\", \"::\", \"\",\n \"\", \"\", \"\", \"\"\n].map((e, i)=>to_luastring(e));\n\nclass SemInfo {\n constructor() {\n this.r = NaN;\n this.i = NaN;\n this.ts = null;\n }\n}\n\nclass Token {\n constructor() {\n this.token = NaN;\n this.seminfo = new SemInfo();\n }\n}\n\n/* state of the lexer plus state of the parser when shared by all\n functions */\nclass LexState {\n constructor() {\n this.current = NaN; /* current character (charint) */\n this.linenumber = NaN; /* input line counter */\n this.lastline = NaN; /* line of last token 'consumed' */\n this.t = new Token(); /* current token */\n this.lookahead = new Token(); /* look ahead token */\n this.fs = null; /* current function (parser) */\n this.L = null;\n this.z = null; /* input stream */\n this.buff = null; /* buffer for tokens */\n this.h = null; /* to reuse strings */\n this.dyd = null; /* dynamic structures used by the parser */\n this.source = null; /* current source name */\n this.envn = null; /* environment variable name */\n }\n}\n\nconst save = function(ls, c) {\n let b = ls.buff;\n if (b.n + 1 > b.buffer.length) {\n if (b.buffer.length >= MAX_INT/2)\n lexerror(ls, to_luastring(\"lexical element too long\", true), 0);\n let newsize = b.buffer.length*2;\n luaZ_resizebuffer(ls.L, b, newsize);\n }\n b.buffer[b.n++] = c < 0 ? 255 + c + 1 : c;\n};\n\nconst luaX_token2str = function(ls, token) {\n if (token < FIRST_RESERVED) { /* single-byte symbols? */\n return lobject.luaO_pushfstring(ls.L, to_luastring(\"'%c'\", true), token);\n } else {\n let s = luaX_tokens[token - FIRST_RESERVED];\n if (token < TK_EOS) /* fixed format (symbols and reserved words)? */\n return lobject.luaO_pushfstring(ls.L, to_luastring(\"'%s'\", true), s);\n else /* names, strings, and numerals */\n return s;\n }\n};\n\nconst currIsNewline = function(ls) {\n return ls.current === 10 /* ('\\n').charCodeAt(0) */ || ls.current === 13 /* ('\\r').charCodeAt(0) */;\n};\n\nconst next = function(ls) {\n ls.current = ls.z.zgetc();\n};\n\nconst save_and_next = function(ls) {\n save(ls, ls.current);\n next(ls);\n};\n\n/*\n** creates a new string and anchors it in scanner's table so that\n** it will not be collected until the end of the compilation\n** (by that time it should be anchored somewhere)\n*/\nconst TVtrue = new lobject.TValue(LUA_TBOOLEAN, true);\nconst luaX_newstring = function(ls, str) {\n let L = ls.L;\n let ts = luaS_new(L, str);\n /* HACK: Workaround lack of ltable 'keyfromval' */\n let tpair = ls.h.strong.get(luaS_hashlongstr(ts));\n if (!tpair) { /* not in use yet? */\n let key = new lobject.TValue(LUA_TLNGSTR, ts);\n ltable.luaH_setfrom(L, ls.h, key, TVtrue);\n } else { /* string already present */\n ts = tpair.key.tsvalue(); /* re-use value previously stored */\n }\n return ts;\n};\n\n/*\n** increment line number and skips newline sequence (any of\n** \\n, \\r, \\n\\r, or \\r\\n)\n*/\nconst inclinenumber = function(ls) {\n let old = ls.current;\n lua_assert(currIsNewline(ls));\n next(ls); /* skip '\\n' or '\\r' */\n if (currIsNewline(ls) && ls.current !== old)\n next(ls); /* skip '\\n\\r' or '\\r\\n' */\n if (++ls.linenumber >= MAX_INT)\n lexerror(ls, to_luastring(\"chunk has too many lines\", true), 0);\n};\n\nconst luaX_setinput = function(L, ls, z, source, firstchar) {\n ls.t = {\n token: 0,\n seminfo: new SemInfo()\n };\n ls.L = L;\n ls.current = firstchar;\n ls.lookahead = {\n token: TK_EOS,\n seminfo: new SemInfo()\n };\n ls.z = z;\n ls.fs = null;\n ls.linenumber = 1;\n ls.lastline = 1;\n ls.source = source;\n ls.envn = luaS_bless(L, LUA_ENV);\n luaZ_resizebuffer(L, ls.buff, LUA_MINBUFFER); /* initialize buffer */\n};\n\nconst check_next1 = function(ls, c) {\n if (ls.current === c) {\n next(ls);\n return true;\n }\n\n return false;\n};\n\n/*\n** Check whether current char is in set 'set' (with two chars) and\n** saves it\n*/\nconst check_next2 = function(ls, set) {\n if (ls.current === set[0].charCodeAt(0) || ls.current === set[1].charCodeAt(0)) {\n save_and_next(ls);\n return true;\n }\n\n return false;\n};\n\nconst read_numeral = function(ls, seminfo) {\n let expo = \"Ee\";\n let first = ls.current;\n lua_assert(lisdigit(ls.current));\n save_and_next(ls);\n if (first === 48 /* ('0').charCodeAt(0) */ && check_next2(ls, \"xX\")) /* hexadecimal? */\n expo = \"Pp\";\n\n for (;;) {\n if (check_next2(ls, expo)) /* exponent part? */\n check_next2(ls, \"-+\"); /* optional exponent sign */\n if (lisxdigit(ls.current))\n save_and_next(ls);\n else if (ls.current === 46 /* ('.').charCodeAt(0) */)\n save_and_next(ls);\n else break;\n }\n\n // save(ls, 0);\n\n let obj = new lobject.TValue();\n if (lobject.luaO_str2num(luaZ_buffer(ls.buff), obj) === 0) /* format error? */\n lexerror(ls, to_luastring(\"malformed number\", true), TK_FLT);\n if (obj.ttisinteger()) {\n seminfo.i = obj.value;\n return TK_INT;\n } else {\n lua_assert(obj.ttisfloat());\n seminfo.r = obj.value;\n return TK_FLT;\n }\n};\n\nconst txtToken = function(ls, token) {\n switch (token) {\n case TK_NAME: case TK_STRING:\n case TK_FLT: case TK_INT:\n // save(ls, 0);\n return lobject.luaO_pushfstring(ls.L, to_luastring(\"'%s'\", true), luaZ_buffer(ls.buff));\n default:\n return luaX_token2str(ls, token);\n }\n};\n\nconst lexerror = function(ls, msg, token) {\n msg = ldebug.luaG_addinfo(ls.L, msg, ls.source, ls.linenumber);\n if (token)\n lobject.luaO_pushfstring(ls.L, to_luastring(\"%s near %s\"), msg, txtToken(ls, token));\n ldo.luaD_throw(ls.L, LUA_ERRSYNTAX);\n};\n\nconst luaX_syntaxerror = function(ls, msg) {\n lexerror(ls, msg, ls.t.token);\n};\n\n/*\n** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return\n** its number of '='s; otherwise, return a negative number (-1 iff there\n** are no '='s after initial bracket)\n*/\nconst skip_sep = function(ls) {\n let count = 0;\n let s = ls.current;\n lua_assert(s === 91 /* ('[').charCodeAt(0) */ || s === 93 /* (']').charCodeAt(0) */);\n save_and_next(ls);\n while (ls.current === 61 /* ('=').charCodeAt(0) */) {\n save_and_next(ls);\n count++;\n }\n return ls.current === s ? count : (-count) - 1;\n};\n\nconst read_long_string = function(ls, seminfo, sep) {\n let line = ls.linenumber; /* initial line (for error message) */\n save_and_next(ls); /* skip 2nd '[' */\n\n if (currIsNewline(ls)) /* string starts with a newline? */\n inclinenumber(ls); /* skip it */\n\n let skip = false;\n for (; !skip ;) {\n switch (ls.current) {\n case EOZ: { /* error */\n let what = seminfo ? \"string\" : \"comment\";\n let msg = `unfinished long ${what} (starting at line ${line})`;\n lexerror(ls, to_luastring(msg), TK_EOS);\n break;\n }\n case 93 /* (']').charCodeAt(0) */: {\n if (skip_sep(ls) === sep) {\n save_and_next(ls); /* skip 2nd ']' */\n skip = true;\n }\n break;\n }\n case 10 /* ('\\n').charCodeAt(0) */:\n case 13 /* ('\\r').charCodeAt(0) */: {\n save(ls, 10 /* ('\\n').charCodeAt(0) */);\n inclinenumber(ls);\n if (!seminfo) luaZ_resetbuffer(ls.buff);\n break;\n }\n default: {\n if (seminfo) save_and_next(ls);\n else next(ls);\n }\n }\n }\n\n if (seminfo)\n seminfo.ts = luaX_newstring(ls, ls.buff.buffer.subarray(2 + sep, ls.buff.n - (2 + sep)));\n};\n\nconst esccheck = function(ls, c, msg) {\n if (!c) {\n if (ls.current !== EOZ)\n save_and_next(ls); /* add current to buffer for error message */\n lexerror(ls, msg, TK_STRING);\n }\n};\n\nconst gethexa = function(ls) {\n save_and_next(ls);\n esccheck(ls, lisxdigit(ls.current), to_luastring(\"hexadecimal digit expected\", true));\n return lobject.luaO_hexavalue(ls.current);\n};\n\nconst readhexaesc = function(ls) {\n let r = gethexa(ls);\n r = (r << 4) + gethexa(ls);\n luaZ_buffremove(ls.buff, 2); /* remove saved chars from buffer */\n return r;\n};\n\nconst readutf8desc = function(ls) {\n let i = 4; /* chars to be removed: '\\', 'u', '{', and first digit */\n save_and_next(ls); /* skip 'u' */\n esccheck(ls, ls.current === 123 /* ('{').charCodeAt(0) */, to_luastring(\"missing '{'\", true));\n let r = gethexa(ls); /* must have at least one digit */\n\n save_and_next(ls);\n while (lisxdigit(ls.current)) {\n i++;\n r = (r << 4) + lobject.luaO_hexavalue(ls.current);\n esccheck(ls, r <= 0x10FFFF, to_luastring(\"UTF-8 value too large\", true));\n save_and_next(ls);\n }\n esccheck(ls, ls.current === 125 /* ('}').charCodeAt(0) */, to_luastring(\"missing '}'\", true));\n next(ls); /* skip '}' */\n luaZ_buffremove(ls.buff, i); /* remove saved chars from buffer */\n return r;\n};\n\nconst utf8esc = function(ls) {\n let buff = new Uint8Array(lobject.UTF8BUFFSZ);\n let n = lobject.luaO_utf8esc(buff, readutf8desc(ls));\n for (; n > 0; n--) /* add 'buff' to string */\n save(ls, buff[lobject.UTF8BUFFSZ - n]);\n};\n\nconst readdecesc = function(ls) {\n let r = 0; /* result accumulator */\n let i;\n for (i = 0; i < 3 && lisdigit(ls.current); i++) { /* read up to 3 digits */\n r = 10 * r + ls.current - 48 /* ('0').charCodeAt(0) */;\n save_and_next(ls);\n }\n esccheck(ls, r <= 255, to_luastring(\"decimal escape too large\", true));\n luaZ_buffremove(ls.buff, i); /* remove read digits from buffer */\n return r;\n};\n\nconst read_string = function(ls, del, seminfo) {\n save_and_next(ls); /* keep delimiter (for error messages) */\n\n while (ls.current !== del) {\n switch (ls.current) {\n case EOZ:\n lexerror(ls, to_luastring(\"unfinished string\", true), TK_EOS);\n break;\n case 10 /* ('\\n').charCodeAt(0) */:\n case 13 /* ('\\r').charCodeAt(0) */:\n lexerror(ls, to_luastring(\"unfinished string\", true), TK_STRING);\n break;\n case 92 /* ('\\\\').charCodeAt(0) */: { /* escape sequences */\n save_and_next(ls); /* keep '\\\\' for error messages */\n let will;\n let c;\n switch(ls.current) {\n case 97 /* ('a').charCodeAt(0) */: c = 7 /* \\a isn't valid JS */; will = 'read_save'; break;\n case 98 /* ('b').charCodeAt(0) */: c = 8 /* ('\\b').charCodeAt(0) */; will = 'read_save'; break;\n case 102 /* ('f').charCodeAt(0) */: c = 12 /* ('\\f').charCodeAt(0) */; will = 'read_save'; break;\n case 110 /* ('n').charCodeAt(0) */: c = 10 /* ('\\n').charCodeAt(0) */; will = 'read_save'; break;\n case 114 /* ('r').charCodeAt(0) */: c = 13 /* ('\\r').charCodeAt(0) */; will = 'read_save'; break;\n case 116 /* ('t').charCodeAt(0) */: c = 9 /* ('\\t').charCodeAt(0) */; will = 'read_save'; break;\n case 118 /* ('v').charCodeAt(0) */: c = 11 /* ('\\v').charCodeAt(0) */; will = 'read_save'; break;\n case 120 /* ('x').charCodeAt(0) */: c = readhexaesc(ls); will = 'read_save'; break;\n case 117 /* ('u').charCodeAt(0) */: utf8esc(ls); will = 'no_save'; break;\n case 10 /* ('\\n').charCodeAt(0) */:\n case 13 /* ('\\r').charCodeAt(0) */:\n inclinenumber(ls); c = 10 /* ('\\n').charCodeAt(0) */; will = 'only_save'; break;\n case 92 /* ('\\\\').charCodeAt(0) */:\n case 34 /* ('\"').charCodeAt(0) */:\n case 39 /* ('\\'').charCodeAt(0) */:\n c = ls.current; will = 'read_save'; break;\n case EOZ: will = 'no_save'; break; /* will raise an error next loop */\n case 122 /* ('z').charCodeAt(0) */: { /* zap following span of spaces */\n luaZ_buffremove(ls.buff, 1); /* remove '\\\\' */\n next(ls); /* skip the 'z' */\n while (lisspace(ls.current)) {\n if (currIsNewline(ls)) inclinenumber(ls);\n else next(ls);\n }\n will = 'no_save'; break;\n }\n default: {\n esccheck(ls, lisdigit(ls.current), to_luastring(\"invalid escape sequence\", true));\n c = readdecesc(ls); /* digital escape '\\ddd' */\n will = 'only_save'; break;\n }\n }\n\n if (will === 'read_save')\n next(ls);\n\n if (will === 'read_save' || will === 'only_save') {\n luaZ_buffremove(ls.buff, 1); /* remove '\\\\' */\n save(ls, c);\n }\n\n break;\n }\n default:\n save_and_next(ls);\n }\n }\n save_and_next(ls); /* skip delimiter */\n\n seminfo.ts = luaX_newstring(ls, ls.buff.buffer.subarray(1, ls.buff.n-1));\n};\n\nconst token_to_index = Object.create(null); /* don't want to return true for e.g. 'hasOwnProperty' */\nluaX_tokens.forEach((e, i)=>token_to_index[luaS_hash(e)] = i);\n\nconst isreserved = function(w) {\n let kidx = token_to_index[luaS_hashlongstr(w)];\n return kidx !== void 0 && kidx <= 22;\n};\n\nconst llex = function(ls, seminfo) {\n luaZ_resetbuffer(ls.buff);\n for (;;) {\n lua_assert(typeof ls.current == \"number\"); /* fengari addition */\n switch (ls.current) {\n case 10 /* ('\\n').charCodeAt(0) */:\n case 13 /* ('\\r').charCodeAt(0) */: { /* line breaks */\n inclinenumber(ls);\n break;\n }\n case 32 /* (' ').charCodeAt(0) */:\n case 12 /* ('\\f').charCodeAt(0) */:\n case 9 /* ('\\t').charCodeAt(0) */:\n case 11 /* ('\\v').charCodeAt(0) */: { /* spaces */\n next(ls);\n break;\n }\n case 45 /* ('-').charCodeAt(0) */: { /* '-' or '--' (comment) */\n next(ls);\n if (ls.current !== 45 /* ('-').charCodeAt(0) */) return 45 /* ('-').charCodeAt(0) */;\n /* else is a comment */\n next(ls);\n if (ls.current === 91 /* ('[').charCodeAt(0) */) { /* long comment? */\n let sep = skip_sep(ls);\n luaZ_resetbuffer(ls.buff); /* 'skip_sep' may dirty the buffer */\n if (sep >= 0) {\n read_long_string(ls, null, sep); /* skip long comment */\n luaZ_resetbuffer(ls.buff); /* previous call may dirty the buff. */\n break;\n }\n }\n\n /* else short comment */\n while (!currIsNewline(ls) && ls.current !== EOZ)\n next(ls); /* skip until end of line (or end of file) */\n break;\n }\n case 91 /* ('[').charCodeAt(0) */: { /* long string or simply '[' */\n let sep = skip_sep(ls);\n if (sep >= 0) {\n read_long_string(ls, seminfo, sep);\n return TK_STRING;\n } else if (sep !== -1) /* '[=...' missing second bracket */\n lexerror(ls, to_luastring(\"invalid long string delimiter\", true), TK_STRING);\n return 91 /* ('[').charCodeAt(0) */;\n }\n case 61 /* ('=').charCodeAt(0) */: {\n next(ls);\n if (check_next1(ls, 61 /* ('=').charCodeAt(0) */)) return TK_EQ;\n else return 61 /* ('=').charCodeAt(0) */;\n }\n case 60 /* ('<').charCodeAt(0) */: {\n next(ls);\n if (check_next1(ls, 61 /* ('=').charCodeAt(0) */)) return TK_LE;\n else if (check_next1(ls, 60 /* ('<').charCodeAt(0) */)) return TK_SHL;\n else return 60 /* ('<').charCodeAt(0) */;\n }\n case 62 /* ('>').charCodeAt(0) */: {\n next(ls);\n if (check_next1(ls, 61 /* ('=').charCodeAt(0) */)) return TK_GE;\n else if (check_next1(ls, 62 /* ('>').charCodeAt(0) */)) return TK_SHR;\n else return 62 /* ('>').charCodeAt(0) */;\n }\n case 47 /* ('/').charCodeAt(0) */: {\n next(ls);\n if (check_next1(ls, 47 /* ('/').charCodeAt(0) */)) return TK_IDIV;\n else return 47 /* ('/').charCodeAt(0) */;\n }\n case 126 /* ('~').charCodeAt(0) */: {\n next(ls);\n if (check_next1(ls, 61 /* ('=').charCodeAt(0) */)) return TK_NE;\n else return 126 /* ('~').charCodeAt(0) */;\n }\n case 58 /* (':').charCodeAt(0) */: {\n next(ls);\n if (check_next1(ls, 58 /* (':').charCodeAt(0) */)) return TK_DBCOLON;\n else return 58 /* (':').charCodeAt(0) */;\n }\n case 34 /* ('\"').charCodeAt(0) */:\n case 39 /* ('\\'').charCodeAt(0) */: { /* short literal strings */\n read_string(ls, ls.current, seminfo);\n return TK_STRING;\n }\n case 46 /* ('.').charCodeAt(0) */: { /* '.', '..', '...', or number */\n save_and_next(ls);\n if (check_next1(ls, 46 /* ('.').charCodeAt(0) */)) {\n if (check_next1(ls, 46 /* ('.').charCodeAt(0) */))\n return TK_DOTS; /* '...' */\n else return TK_CONCAT; /* '..' */\n }\n else if (!lisdigit(ls.current)) return 46 /* ('.').charCodeAt(0) */;\n else return read_numeral(ls, seminfo);\n }\n case 48 /* ('0').charCodeAt(0) */: case 49 /* ('1').charCodeAt(0) */: case 50 /* ('2').charCodeAt(0) */: case 51 /* ('3').charCodeAt(0) */: case 52 /* ('4').charCodeAt(0) */:\n case 53 /* ('5').charCodeAt(0) */: case 54 /* ('6').charCodeAt(0) */: case 55 /* ('7').charCodeAt(0) */: case 56 /* ('8').charCodeAt(0) */: case 57 /* ('9').charCodeAt(0) */: {\n return read_numeral(ls, seminfo);\n }\n case EOZ: {\n return TK_EOS;\n }\n default: {\n if (lislalpha(ls.current)) { /* identifier or reserved word? */\n do {\n save_and_next(ls);\n } while (lislalnum(ls.current));\n let ts = luaX_newstring(ls, luaZ_buffer(ls.buff));\n seminfo.ts = ts;\n let kidx = token_to_index[luaS_hashlongstr(ts)];\n if (kidx !== void 0 && kidx <= 22) /* reserved word? */\n return kidx + FIRST_RESERVED;\n else\n return TK_NAME;\n } else { /* single-char tokens (+ - / ...) */\n let c = ls.current;\n next(ls);\n return c;\n }\n }\n }\n }\n};\n\nconst luaX_next = function(ls) {\n ls.lastline = ls.linenumber;\n if (ls.lookahead.token !== TK_EOS) { /* is there a look-ahead token? */\n ls.t.token = ls.lookahead.token; /* use this one */\n ls.t.seminfo.i = ls.lookahead.seminfo.i;\n ls.t.seminfo.r = ls.lookahead.seminfo.r;\n ls.t.seminfo.ts = ls.lookahead.seminfo.ts;\n ls.lookahead.token = TK_EOS; /* and discharge it */\n } else\n ls.t.token = llex(ls, ls.t.seminfo); /* read next token */\n};\n\nconst luaX_lookahead = function(ls) {\n lua_assert(ls.lookahead.token === TK_EOS);\n ls.lookahead.token = llex(ls, ls.lookahead.seminfo);\n return ls.lookahead.token;\n};\n\nmodule.exports.FIRST_RESERVED = FIRST_RESERVED;\nmodule.exports.LUA_ENV = LUA_ENV;\nmodule.exports.LexState = LexState;\nmodule.exports.RESERVED = RESERVED;\nmodule.exports.isreserved = isreserved;\nmodule.exports.luaX_lookahead = luaX_lookahead;\nmodule.exports.luaX_newstring = luaX_newstring;\nmodule.exports.luaX_next = luaX_next;\nmodule.exports.luaX_setinput = luaX_setinput;\nmodule.exports.luaX_syntaxerror = luaX_syntaxerror;\nmodule.exports.luaX_token2str = luaX_token2str;\nmodule.exports.luaX_tokens = luaX_tokens;\n","\"use strict\";\n\nconst { luastring_of } = require('./defs.js');\n\nconst luai_ctype_ = luastring_of(\n 0x00, /* EOZ */\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */\n 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */\n 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,\n 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */\n 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,\n 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */\n 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,\n 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */\n 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05,\n 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */\n 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,\n 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */\n 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00,\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */\n 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n);\n\nconst ALPHABIT = 0;\nconst DIGITBIT = 1;\nconst PRINTBIT = 2;\nconst SPACEBIT = 3;\nconst XDIGITBIT = 4;\n\nconst lisdigit = function(c) {\n return (luai_ctype_[c+1] & (1<locvars' */\n this.nactvar = NaN; /* number of active local variables */\n this.nups = NaN; /* number of upvalues */\n this.freereg = NaN; /* first free register */\n }\n}\n\n/* description of active local variable */\nclass Vardesc {\n constructor() {\n this.idx = NaN; /* variable index in stack */\n }\n}\n\n\n/* description of pending goto statements and label statements */\nclass Labeldesc {\n constructor() {\n this.name = null; /* label identifier */\n this.pc = NaN; /* position in code */\n this.line = NaN; /* line where it appeared */\n this.nactvar = NaN; /* local level where it appears in current block */\n }\n}\n\n\n/* list of labels or gotos */\nclass Labellist {\n constructor() {\n this.arr = []; /* array */\n this.n = NaN; /* number of entries in use */\n this.size = NaN; /* array size */\n }\n}\n\n/* dynamic structures used by the parser */\nclass Dyndata {\n constructor() {\n this.actvar = { /* list of active local variables */\n arr: [],\n n: NaN,\n size: NaN\n };\n this.gt = new Labellist();\n this.label = new Labellist();\n }\n}\n\nconst semerror = function(ls, msg) {\n ls.t.token = 0; /* remove \"near \" from final message */\n llex.luaX_syntaxerror(ls, msg);\n};\n\nconst error_expected = function(ls, token) {\n llex.luaX_syntaxerror(ls, lobject.luaO_pushfstring(ls.L, to_luastring(\"%s expected\", true), llex.luaX_token2str(ls, token)));\n};\n\nconst errorlimit = function(fs, limit, what) {\n let L = fs.ls.L;\n let line = fs.f.linedefined;\n let where = (line === 0)\n ? to_luastring(\"main function\", true)\n : lobject.luaO_pushfstring(L, to_luastring(\"function at line %d\", true), line);\n let msg = lobject.luaO_pushfstring(L, to_luastring(\"too many %s (limit is %d) in %s\", true),\n what, limit, where);\n llex.luaX_syntaxerror(fs.ls, msg);\n};\n\nconst checklimit = function(fs, v, l, what) {\n if (v > l) errorlimit(fs, l, what);\n};\n\nconst testnext = function(ls, c) {\n if (ls.t.token === c) {\n llex.luaX_next(ls);\n return true;\n }\n\n return false;\n};\n\nconst check = function(ls, c) {\n if (ls.t.token !== c)\n error_expected(ls, c);\n};\n\nconst checknext = function(ls, c) {\n check(ls, c);\n llex.luaX_next(ls);\n};\n\nconst check_condition = function(ls, c, msg) {\n if (!c)\n llex.luaX_syntaxerror(ls, msg);\n};\n\nconst check_match = function(ls, what, who, where) {\n if (!testnext(ls, what)) {\n if (where === ls.linenumber)\n error_expected(ls, what);\n else\n llex.luaX_syntaxerror(ls, lobject.luaO_pushfstring(ls.L,\n to_luastring(\"%s expected (to close %s at line %d)\"),\n llex.luaX_token2str(ls, what), llex.luaX_token2str(ls, who), where));\n }\n};\n\nconst str_checkname = function(ls) {\n check(ls, R.TK_NAME);\n let ts = ls.t.seminfo.ts;\n llex.luaX_next(ls);\n return ts;\n};\n\nconst init_exp = function(e, k, i) {\n e.f = e.t = NO_JUMP;\n e.k = k;\n e.u.info = i;\n};\n\nconst codestring = function(ls, e, s) {\n init_exp(e, expkind.VK, luaK_stringK(ls.fs, s));\n};\n\nconst checkname = function(ls, e) {\n codestring(ls, e, str_checkname(ls));\n};\n\nconst registerlocalvar = function(ls, varname) {\n let fs = ls.fs;\n let f = fs.f;\n f.locvars[fs.nlocvars] = new lobject.LocVar();\n f.locvars[fs.nlocvars].varname = varname;\n return fs.nlocvars++;\n};\n\nconst new_localvar = function(ls, name) {\n let fs = ls.fs;\n let dyd = ls.dyd;\n let reg = registerlocalvar(ls, name);\n checklimit(fs, dyd.actvar.n + 1 - fs.firstlocal, MAXVARS, to_luastring(\"local variables\", true));\n dyd.actvar.arr[dyd.actvar.n] = new Vardesc();\n dyd.actvar.arr[dyd.actvar.n].idx = reg;\n dyd.actvar.n++;\n};\n\nconst new_localvarliteral = function(ls, name) {\n new_localvar(ls, llex.luaX_newstring(ls, to_luastring(name, true)));\n};\n\nconst getlocvar = function(fs, i) {\n let idx = fs.ls.dyd.actvar.arr[fs.firstlocal + i].idx;\n lua_assert(idx < fs.nlocvars);\n return fs.f.locvars[idx];\n};\n\nconst adjustlocalvars = function(ls, nvars) {\n let fs = ls.fs;\n fs.nactvar = fs.nactvar + nvars;\n for (; nvars; nvars--)\n getlocvar(fs, fs.nactvar - nvars).startpc = fs.pc;\n};\n\nconst removevars = function(fs, tolevel) {\n fs.ls.dyd.actvar.n -= fs.nactvar - tolevel;\n while (fs.nactvar > tolevel)\n getlocvar(fs, --fs.nactvar).endpc = fs.pc;\n};\n\nconst searchupvalue = function(fs, name) {\n let up = fs.f.upvalues;\n for (let i = 0; i < fs.nups; i++) {\n if (eqstr(up[i].name, name))\n return i;\n }\n return -1; /* not found */\n};\n\nconst newupvalue = function(fs, name, v) {\n let f = fs.f;\n checklimit(fs, fs.nups + 1, lfunc.MAXUPVAL, to_luastring(\"upvalues\", true));\n f.upvalues[fs.nups] = {\n instack: v.k === expkind.VLOCAL,\n idx: v.u.info,\n name: name\n };\n return fs.nups++;\n};\n\nconst searchvar = function(fs, n) {\n for (let i = fs.nactvar - 1; i >= 0; i--) {\n if (eqstr(n, getlocvar(fs, i).varname))\n return i;\n }\n\n return -1;\n};\n\n/*\n** Mark block where variable at given level was defined\n** (to emit close instructions later).\n*/\nconst markupval = function(fs, level) {\n let bl = fs.bl;\n while (bl.nactvar > level)\n bl = bl.previous;\n bl.upval = 1;\n};\n\n/*\n** Find variable with given name 'n'. If it is an upvalue, add this\n** upvalue into all intermediate functions.\n*/\nconst singlevaraux = function(fs, n, vr, base) {\n if (fs === null) /* no more levels? */\n init_exp(vr, expkind.VVOID, 0); /* default is global */\n else {\n let v = searchvar(fs, n); /* look up locals at current level */\n if (v >= 0) { /* found? */\n init_exp(vr, expkind.VLOCAL, v); /* variable is local */\n if (!base)\n markupval(fs, v); /* local will be used as an upval */\n } else { /* not found as local at current level; try upvalues */\n let idx = searchupvalue(fs, n); /* try existing upvalues */\n if (idx < 0) { /* not found? */\n singlevaraux(fs.prev, n, vr, 0); /* try upper levels */\n if (vr.k === expkind.VVOID) /* not found? */\n return; /* it is a global */\n /* else was LOCAL or UPVAL */\n idx = newupvalue(fs, n, vr); /* will be a new upvalue */\n }\n init_exp(vr, expkind.VUPVAL, idx); /* new or old upvalue */\n }\n }\n};\n\nconst singlevar = function(ls, vr) {\n let varname = str_checkname(ls);\n let fs = ls.fs;\n singlevaraux(fs, varname, vr, 1);\n if (vr.k === expkind.VVOID) { /* is global name? */\n let key = new expdesc();\n singlevaraux(fs, ls.envn, vr, 1); /* get environment variable */\n lua_assert(vr.k !== expkind.VVOID); /* this one must exist */\n codestring(ls, key, varname); /* key is variable name */\n luaK_indexed(fs, vr, key); /* env[varname] */\n }\n};\n\nconst adjust_assign = function(ls, nvars, nexps, e) {\n let fs = ls.fs;\n let extra = nvars - nexps;\n if (hasmultret(e.k)) {\n extra++; /* includes call itself */\n if (extra < 0) extra = 0;\n luaK_setreturns(fs, e, extra); /* last exp. provides the difference */\n if (extra > 1) luaK_reserveregs(fs, extra - 1);\n } else {\n if (e.k !== expkind.VVOID) luaK_exp2nextreg(fs, e); /* close last expression */\n if (extra > 0) {\n let reg = fs.freereg;\n luaK_reserveregs(fs, extra);\n luaK_nil(fs, reg, extra);\n }\n }\n if (nexps > nvars)\n ls.fs.freereg -= nexps - nvars; /* remove extra values */\n};\n\nconst enterlevel = function(ls) {\n let L = ls.L;\n ++L.nCcalls;\n checklimit(ls.fs, L.nCcalls, LUAI_MAXCCALLS, to_luastring(\"JS levels\", true));\n};\n\nconst leavelevel = function(ls) {\n return ls.L.nCcalls--;\n};\n\nconst closegoto = function(ls, g, label) {\n let fs = ls.fs;\n let gl = ls.dyd.gt;\n let gt = gl.arr[g];\n lua_assert(eqstr(gt.name, label.name));\n if (gt.nactvar < label.nactvar) {\n let vname = getlocvar(fs, gt.nactvar).varname;\n let msg = lobject.luaO_pushfstring(ls.L,\n to_luastring(\" at line %d jumps into the scope of local '%s'\"),\n gt.name.getstr(), gt.line, vname.getstr());\n semerror(ls, msg);\n }\n luaK_patchlist(fs, gt.pc, label.pc);\n /* remove goto from pending list */\n for (let i = g; i < gl.n - 1; i++)\n gl.arr[i] = gl.arr[i + 1];\n gl.n--;\n};\n\n/*\n** try to close a goto with existing labels; this solves backward jumps\n*/\nconst findlabel = function(ls, g) {\n let bl = ls.fs.bl;\n let dyd = ls.dyd;\n let gt = dyd.gt.arr[g];\n /* check labels in current block for a match */\n for (let i = bl.firstlabel; i < dyd.label.n; i++) {\n let lb = dyd.label.arr[i];\n if (eqstr(lb.name, gt.name)) { /* correct label? */\n if (gt.nactvar > lb.nactvar && (bl.upval || dyd.label.n > bl.firstlabel))\n luaK_patchclose(ls.fs, gt.pc, lb.nactvar);\n closegoto(ls, g, lb); /* close it */\n return true;\n }\n }\n return false; /* label not found; cannot close goto */\n};\n\nconst newlabelentry = function(ls, l, name, line, pc) {\n let n = l.n;\n l.arr[n] = new Labeldesc();\n l.arr[n].name = name;\n l.arr[n].line = line;\n l.arr[n].nactvar = ls.fs.nactvar;\n l.arr[n].pc = pc;\n l.n = n + 1;\n return n;\n};\n\n/*\n** check whether new label 'lb' matches any pending gotos in current\n** block; solves forward jumps\n*/\nconst findgotos = function(ls, lb) {\n let gl = ls.dyd.gt;\n let i = ls.fs.bl.firstgoto;\n while (i < gl.n) {\n if (eqstr(gl.arr[i].name, lb.name))\n closegoto(ls, i, lb);\n else\n i++;\n }\n};\n\n/*\n** export pending gotos to outer level, to check them against\n** outer labels; if the block being exited has upvalues, and\n** the goto exits the scope of any variable (which can be the\n** upvalue), close those variables being exited.\n*/\nconst movegotosout = function(fs, bl) {\n let i = bl.firstgoto;\n let gl = fs.ls.dyd.gt;\n /* correct pending gotos to current block and try to close it\n with visible labels */\n while (i < gl.n) {\n let gt = gl.arr[i];\n if (gt.nactvar > bl.nactvar) {\n if (bl.upval)\n luaK_patchclose(fs, gt.pc, bl.nactvar);\n gt.nactvar = bl.nactvar;\n }\n if (!findlabel(fs.ls, i))\n i++; /* move to next one */\n }\n};\n\nconst enterblock = function(fs, bl, isloop) {\n bl.isloop = isloop;\n bl.nactvar = fs.nactvar;\n bl.firstlabel = fs.ls.dyd.label.n;\n bl.firstgoto = fs.ls.dyd.gt.n;\n bl.upval = 0;\n bl.previous = fs.bl;\n fs.bl = bl;\n lua_assert(fs.freereg === fs.nactvar);\n};\n\n/*\n** create a label named 'break' to resolve break statements\n*/\nconst breaklabel = function(ls) {\n let n = luaS_newliteral(ls.L, \"break\");\n let l = newlabelentry(ls, ls.dyd.label, n, 0, ls.fs.pc);\n findgotos(ls, ls.dyd.label.arr[l]);\n};\n\n/*\n** generates an error for an undefined 'goto'; choose appropriate\n** message when label name is a reserved word (which can only be 'break')\n*/\nconst undefgoto = function(ls, gt) {\n let msg = llex.isreserved(gt.name)\n ? \"<%s> at line %d not inside a loop\"\n : \"no visible label '%s' for at line %d\";\n msg = lobject.luaO_pushfstring(ls.L, to_luastring(msg), gt.name.getstr(), gt.line);\n semerror(ls, msg);\n};\n\n/*\n** adds a new prototype into list of prototypes\n*/\nconst addprototype = function(ls) {\n let L = ls.L;\n let clp = new Proto(L);\n let fs = ls.fs;\n let f = fs.f; /* prototype of current function */\n f.p[fs.np++] = clp;\n return clp;\n};\n\n/*\n** codes instruction to create new closure in parent function.\n*/\nconst codeclosure = function(ls, v) {\n let fs = ls.fs.prev;\n init_exp(v, expkind.VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs.np -1));\n luaK_exp2nextreg(fs, v); /* fix it at the last register */\n};\n\nconst open_func = function(ls, fs, bl) {\n fs.prev = ls.fs; /* linked list of funcstates */\n fs.ls = ls;\n ls.fs = fs;\n fs.pc = 0;\n fs.lasttarget = 0;\n fs.jpc = NO_JUMP;\n fs.freereg = 0;\n fs.nk = 0;\n fs.np = 0;\n fs.nups = 0;\n fs.nlocvars = 0;\n fs.nactvar = 0;\n fs.firstlocal = ls.dyd.actvar.n;\n fs.bl = null;\n let f = fs.f;\n f.source = ls.source;\n f.maxstacksize = 2; /* registers 0/1 are always valid */\n enterblock(fs, bl, false);\n};\n\nconst leaveblock = function(fs) {\n let bl = fs.bl;\n let ls = fs.ls;\n if (bl.previous && bl.upval) {\n /* create a 'jump to here' to close upvalues */\n let j = luaK_jump(fs);\n luaK_patchclose(fs, j , bl.nactvar);\n luaK_patchtohere(fs, j);\n }\n\n if (bl.isloop)\n breaklabel(ls); /* close pending breaks */\n\n fs.bl = bl.previous;\n removevars(fs, bl.nactvar);\n lua_assert(bl.nactvar === fs.nactvar);\n fs.freereg = fs.nactvar; /* free registers */\n ls.dyd.label.n = bl.firstlabel; /* remove local labels */\n if (bl.previous) /* inner block? */\n movegotosout(fs, bl); /* update pending gotos to outer block */\n else if (bl.firstgoto < ls.dyd.gt.n) /* pending gotos in outer block? */\n undefgoto(ls, ls.dyd.gt.arr[bl.firstgoto]); /* error */\n};\n\nconst close_func = function(ls) {\n let fs = ls.fs;\n luaK_ret(fs, 0, 0); /* final return */\n leaveblock(fs);\n lua_assert(fs.bl === null);\n ls.fs = fs.prev;\n};\n\n/*============================================================*/\n/* GRAMMAR RULES */\n/*============================================================*/\n\nconst block_follow = function(ls, withuntil) {\n switch (ls.t.token) {\n case R.TK_ELSE: case R.TK_ELSEIF:\n case R.TK_END: case R.TK_EOS:\n return true;\n case R.TK_UNTIL: return withuntil;\n default: return false;\n }\n};\n\nconst statlist = function(ls) {\n /* statlist -> { stat [';'] } */\n while (!block_follow(ls, 1)) {\n if (ls.t.token === R.TK_RETURN) {\n statement(ls);\n return; /* 'return' must be last statement */\n }\n statement(ls);\n }\n};\n\nconst fieldsel = function(ls, v) {\n /* fieldsel -> ['.' | ':'] NAME */\n let fs = ls.fs;\n let key = new expdesc();\n luaK_exp2anyregup(fs, v);\n llex.luaX_next(ls); /* skip the dot or colon */\n checkname(ls, key);\n luaK_indexed(fs, v, key);\n};\n\nconst yindex = function(ls, v) {\n /* index -> '[' expr ']' */\n llex.luaX_next(ls); /* skip the '[' */\n expr(ls, v);\n luaK_exp2val(ls.fs, v);\n checknext(ls, 93 /* (']').charCodeAt(0) */);\n};\n\n/*\n** {======================================================================\n** Rules for Constructors\n** =======================================================================\n*/\n\nclass ConsControl {\n constructor() {\n this.v = new expdesc(); /* last list item read */\n this.t = new expdesc(); /* table descriptor */\n this.nh = NaN; /* total number of 'record' elements */\n this.na = NaN; /* total number of array elements */\n this.tostore = NaN; /* number of array elements pending to be stored */\n }\n}\n\nconst recfield = function(ls, cc) {\n /* recfield -> (NAME | '['exp1']') = exp1 */\n let fs = ls.fs;\n let reg = ls.fs.freereg;\n let key = new expdesc();\n let val = new expdesc();\n\n if (ls.t.token === R.TK_NAME) {\n checklimit(fs, cc.nh, MAX_INT, to_luastring(\"items in a constructor\", true));\n checkname(ls, key);\n } else /* ls->t.token === '[' */\n yindex(ls, key);\n cc.nh++;\n checknext(ls, 61 /* ('=').charCodeAt(0) */);\n let rkkey = luaK_exp2RK(fs, key);\n expr(ls, val);\n luaK_codeABC(fs, OP_SETTABLE, cc.t.u.info, rkkey, luaK_exp2RK(fs, val));\n fs.freereg = reg; /* free registers */\n};\n\nconst closelistfield = function(fs, cc) {\n if (cc.v.k === expkind.VVOID) return; /* there is no list item */\n luaK_exp2nextreg(fs, cc.v);\n cc.v.k = expkind.VVOID;\n if (cc.tostore === LFIELDS_PER_FLUSH) {\n luaK_setlist(fs, cc.t.u.info, cc.na, cc.tostore); /* flush */\n cc.tostore = 0; /* no more items pending */\n }\n};\n\nconst lastlistfield = function(fs, cc) {\n if (cc.tostore === 0) return;\n if (hasmultret(cc.v.k)) {\n luaK_setmultret(fs, cc.v);\n luaK_setlist(fs, cc.t.u.info, cc.na, LUA_MULTRET);\n cc.na--; /* do not count last expression (unknown number of elements) */\n } else {\n if (cc.v.k !== expkind.VVOID)\n luaK_exp2nextreg(fs, cc.v);\n luaK_setlist(fs, cc.t.u.info, cc.na, cc.tostore);\n }\n};\n\nconst listfield = function(ls, cc) {\n /* listfield -> exp */\n expr(ls, cc.v);\n checklimit(ls.fs, cc.na, MAX_INT, to_luastring(\"items in a constructor\", true));\n cc.na++;\n cc.tostore++;\n};\n\nconst field = function(ls, cc) {\n /* field -> listfield | recfield */\n switch (ls.t.token) {\n case R.TK_NAME: { /* may be 'listfield' or 'recfield' */\n if (llex.luaX_lookahead(ls) !== 61 /* ('=').charCodeAt(0) */) /* expression? */\n listfield(ls, cc);\n else\n recfield(ls, cc);\n break;\n }\n case 91 /* ('[').charCodeAt(0) */: {\n recfield(ls, cc);\n break;\n }\n default: {\n listfield(ls, cc);\n break;\n }\n }\n};\n\nconst constructor = function(ls, t) {\n /* constructor -> '{' [ field { sep field } [sep] ] '}'\n sep -> ',' | ';' */\n let fs = ls.fs;\n let line = ls.linenumber;\n let pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);\n let cc = new ConsControl();\n cc.na = cc.nh = cc.tostore = 0;\n cc.t = t;\n init_exp(t, expkind.VRELOCABLE, pc);\n init_exp(cc.v, expkind.VVOID, 0); /* no value (yet) */\n luaK_exp2nextreg(ls.fs, t); /* fix it at stack top */\n checknext(ls, 123 /* ('{').charCodeAt(0) */);\n do {\n lua_assert(cc.v.k === expkind.VVOID || cc.tostore > 0);\n if (ls.t.token === 125 /* ('}').charCodeAt(0) */) break;\n closelistfield(fs, cc);\n field(ls, cc);\n } while (testnext(ls, 44 /* (',').charCodeAt(0) */) || testnext(ls, 59 /* (';').charCodeAt(0) */));\n check_match(ls, 125 /* ('}').charCodeAt(0) */, 123 /* ('{').charCodeAt(0) */, line);\n lastlistfield(fs, cc);\n SETARG_B(fs.f.code[pc], lobject.luaO_int2fb(cc.na)); /* set initial array size */\n SETARG_C(fs.f.code[pc], lobject.luaO_int2fb(cc.nh)); /* set initial table size */\n};\n\n/* }====================================================================== */\n\nconst parlist = function(ls) {\n /* parlist -> [ param { ',' param } ] */\n let fs = ls.fs;\n let f = fs.f;\n let nparams = 0;\n f.is_vararg = false;\n if (ls.t.token !== 41 /* (')').charCodeAt(0) */) { /* is 'parlist' not empty? */\n do {\n switch (ls.t.token) {\n case R.TK_NAME: { /* param -> NAME */\n new_localvar(ls, str_checkname(ls));\n nparams++;\n break;\n }\n case R.TK_DOTS: { /* param -> '...' */\n llex.luaX_next(ls);\n f.is_vararg = true; /* declared vararg */\n break;\n }\n default: llex.luaX_syntaxerror(ls, to_luastring(\" or '...' expected\", true));\n }\n } while(!f.is_vararg && testnext(ls, 44 /* (',').charCodeAt(0) */));\n }\n adjustlocalvars(ls, nparams);\n f.numparams = fs.nactvar;\n luaK_reserveregs(fs, fs.nactvar); /* reserve register for parameters */\n};\n\nconst body = function(ls, e, ismethod, line) {\n /* body -> '(' parlist ')' block END */\n let new_fs = new FuncState();\n let bl = new BlockCnt();\n new_fs.f = addprototype(ls);\n new_fs.f.linedefined = line;\n open_func(ls, new_fs, bl);\n checknext(ls, 40 /* ('(').charCodeAt(0) */);\n if (ismethod) {\n new_localvarliteral(ls, \"self\"); /* create 'self' parameter */\n adjustlocalvars(ls, 1);\n }\n parlist(ls);\n checknext(ls, 41 /* (')').charCodeAt(0) */);\n statlist(ls);\n new_fs.f.lastlinedefined = ls.linenumber;\n check_match(ls, R.TK_END, R.TK_FUNCTION, line);\n codeclosure(ls, e);\n close_func(ls);\n};\n\nconst explist = function(ls, v) {\n /* explist -> expr { ',' expr } */\n let n = 1; /* at least one expression */\n expr(ls, v);\n while (testnext(ls, 44 /* (',').charCodeAt(0) */)) {\n luaK_exp2nextreg(ls.fs, v);\n expr(ls, v);\n n++;\n }\n return n;\n};\n\nconst funcargs = function(ls, f, line) {\n let fs = ls.fs;\n let args = new expdesc();\n switch (ls.t.token) {\n case 40 /* ('(').charCodeAt(0) */: { /* funcargs -> '(' [ explist ] ')' */\n llex.luaX_next(ls);\n if (ls.t.token === 41 /* (')').charCodeAt(0) */) /* arg list is empty? */\n args.k = expkind.VVOID;\n else {\n explist(ls, args);\n luaK_setmultret(fs, args);\n }\n check_match(ls, 41 /* (')').charCodeAt(0) */, 40 /* ('(').charCodeAt(0) */, line);\n break;\n }\n case 123 /* ('{').charCodeAt(0) */: { /* funcargs -> constructor */\n constructor(ls, args);\n break;\n }\n case R.TK_STRING: { /* funcargs -> STRING */\n codestring(ls, args, ls.t.seminfo.ts);\n llex.luaX_next(ls); /* must use 'seminfo' before 'next' */\n break;\n }\n default: {\n llex.luaX_syntaxerror(ls, to_luastring(\"function arguments expected\", true));\n }\n }\n lua_assert(f.k === expkind.VNONRELOC);\n let nparams;\n let base = f.u.info; /* base register for call */\n if (hasmultret(args.k))\n nparams = LUA_MULTRET; /* open call */\n else {\n if (args.k !== expkind.VVOID)\n luaK_exp2nextreg(fs, args); /* close last argument */\n nparams = fs.freereg - (base+1);\n }\n init_exp(f, expkind.VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));\n luaK_fixline(fs, line);\n fs.freereg = base + 1; /* call remove function and arguments and leaves (unless changed) one result */\n};\n\n/*\n** {======================================================================\n** Expression parsing\n** =======================================================================\n*/\n\nconst primaryexp = function(ls, v) {\n /* primaryexp -> NAME | '(' expr ')' */\n switch (ls.t.token) {\n case 40 /* ('(').charCodeAt(0) */: {\n let line = ls.linenumber;\n llex.luaX_next(ls);\n expr(ls, v);\n check_match(ls, 41 /* (')').charCodeAt(0) */, 40 /* ('(').charCodeAt(0) */, line);\n luaK_dischargevars(ls.fs, v);\n return;\n }\n case R.TK_NAME: {\n singlevar(ls, v);\n return;\n }\n default: {\n llex.luaX_syntaxerror(ls, to_luastring(\"unexpected symbol\", true));\n }\n }\n};\n\nconst suffixedexp = function(ls, v) {\n /* suffixedexp ->\n primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */\n let fs = ls.fs;\n let line = ls.linenumber;\n primaryexp(ls, v);\n for (;;) {\n switch (ls.t.token) {\n case 46 /* ('.').charCodeAt(0) */: { /* fieldsel */\n fieldsel(ls, v);\n break;\n }\n case 91 /* ('[').charCodeAt(0) */: { /* '[' exp1 ']' */\n let key = new expdesc();\n luaK_exp2anyregup(fs, v);\n yindex(ls, key);\n luaK_indexed(fs, v, key);\n break;\n }\n case 58 /* (':').charCodeAt(0) */: { /* ':' NAME funcargs */\n let key = new expdesc();\n llex.luaX_next(ls);\n checkname(ls, key);\n luaK_self(fs, v, key);\n funcargs(ls, v, line);\n break;\n }\n case 40 /* ('(').charCodeAt(0) */: case R.TK_STRING: case 123 /* ('{').charCodeAt(0) */: { /* funcargs */\n luaK_exp2nextreg(fs, v);\n funcargs(ls, v, line);\n break;\n }\n default: return;\n }\n }\n};\n\nconst simpleexp = function(ls, v) {\n /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... |\n constructor | FUNCTION body | suffixedexp */\n switch (ls.t.token) {\n case R.TK_FLT: {\n init_exp(v, expkind.VKFLT, 0);\n v.u.nval = ls.t.seminfo.r;\n break;\n }\n case R.TK_INT: {\n init_exp(v, expkind.VKINT, 0);\n v.u.ival = ls.t.seminfo.i;\n break;\n }\n case R.TK_STRING: {\n codestring(ls, v, ls.t.seminfo.ts);\n break;\n }\n case R.TK_NIL: {\n init_exp(v, expkind.VNIL, 0);\n break;\n }\n case R.TK_TRUE: {\n init_exp(v, expkind.VTRUE, 0);\n break;\n }\n case R.TK_FALSE: {\n init_exp(v, expkind.VFALSE, 0);\n break;\n }\n case R.TK_DOTS: { /* vararg */\n let fs = ls.fs;\n check_condition(ls, fs.f.is_vararg, to_luastring(\"cannot use '...' outside a vararg function\", true));\n init_exp(v, expkind.VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));\n break;\n }\n case 123 /* ('{').charCodeAt(0) */: { /* constructor */\n constructor(ls, v);\n return;\n }\n case R.TK_FUNCTION: {\n llex.luaX_next(ls);\n body(ls, v, 0, ls.linenumber);\n return;\n }\n default: {\n suffixedexp(ls, v);\n return;\n }\n }\n llex.luaX_next(ls);\n};\n\nconst getunopr = function(op) {\n switch (op) {\n case R.TK_NOT: return OPR_NOT;\n case 45 /* ('-').charCodeAt(0) */: return OPR_MINUS;\n case 126 /* ('~').charCodeAt(0) */: return OPR_BNOT;\n case 35 /* ('#').charCodeAt(0) */: return OPR_LEN;\n default: return OPR_NOUNOPR;\n }\n};\n\nconst getbinopr = function(op) {\n switch (op) {\n case 43 /* ('+').charCodeAt(0) */: return OPR_ADD;\n case 45 /* ('-').charCodeAt(0) */: return OPR_SUB;\n case 42 /* ('*').charCodeAt(0) */: return OPR_MUL;\n case 37 /* ('%').charCodeAt(0) */: return OPR_MOD;\n case 94 /* ('^').charCodeAt(0) */: return OPR_POW;\n case 47 /* ('/').charCodeAt(0) */: return OPR_DIV;\n case R.TK_IDIV: return OPR_IDIV;\n case 38 /* ('&').charCodeAt(0) */: return OPR_BAND;\n case 124 /* ('|').charCodeAt(0) */: return OPR_BOR;\n case 126 /* ('~').charCodeAt(0) */: return OPR_BXOR;\n case R.TK_SHL: return OPR_SHL;\n case R.TK_SHR: return OPR_SHR;\n case R.TK_CONCAT: return OPR_CONCAT;\n case R.TK_NE: return OPR_NE;\n case R.TK_EQ: return OPR_EQ;\n case 60 /* ('<').charCodeAt(0) */: return OPR_LT;\n case R.TK_LE: return OPR_LE;\n case 62 /* ('>').charCodeAt(0) */: return OPR_GT;\n case R.TK_GE: return OPR_GE;\n case R.TK_AND: return OPR_AND;\n case R.TK_OR: return OPR_OR;\n default: return OPR_NOBINOPR;\n }\n};\n\nconst priority = [ /* ORDER OPR */\n {left: 10, right: 10}, {left: 10, right: 10}, /* '+' '-' */\n {left: 11, right: 11}, {left: 11, right: 11}, /* '*' '%' */\n {left: 14, right: 13}, /* '^' (right associative) */\n {left: 11, right: 11}, {left: 11, right: 11}, /* '/' '//' */\n {left: 6, right: 6}, {left: 4, right: 4}, {left: 5, right: 5}, /* '&' '|' '~' */\n {left: 7, right: 7}, {left: 7, right: 7}, /* '<<' '>>' */\n {left: 9, right: 8}, /* '..' (right associative) */\n {left: 3, right: 3}, {left: 3, right: 3}, {left: 3, right: 3}, /* ==, <, <= */\n {left: 3, right: 3}, {left: 3, right: 3}, {left: 3, right: 3}, /* ~=, >, >= */\n {left: 2, right: 2}, {left: 1, right: 1} /* and, or */\n];\n\nconst UNARY_PRIORITY = 12;\n\n/*\n** subexpr -> (simpleexp | unop subexpr) { binop subexpr }\n** where 'binop' is any binary operator with a priority higher than 'limit'\n*/\nconst subexpr = function(ls, v, limit) {\n enterlevel(ls);\n let uop = getunopr(ls.t.token);\n if (uop !== OPR_NOUNOPR) {\n let line = ls.linenumber;\n llex.luaX_next(ls);\n subexpr(ls, v, UNARY_PRIORITY);\n luaK_prefix(ls.fs, uop, v, line);\n } else\n simpleexp(ls, v);\n /* expand while operators have priorities higher than 'limit' */\n let op = getbinopr(ls.t.token);\n while (op !== OPR_NOBINOPR && priority[op].left > limit) {\n let v2 = new expdesc();\n let line = ls.linenumber;\n llex.luaX_next(ls);\n luaK_infix(ls.fs, op, v);\n /* read sub-expression with higher priority */\n let nextop = subexpr(ls, v2, priority[op].right);\n luaK_posfix(ls.fs, op, v, v2, line);\n op = nextop;\n }\n leavelevel(ls);\n return op; /* return first untreated operator */\n};\n\nconst expr = function(ls, v) {\n subexpr(ls, v, 0);\n};\n\n/* }==================================================================== */\n\n\n\n/*\n** {======================================================================\n** Rules for Statements\n** =======================================================================\n*/\n\nconst block = function(ls) {\n /* block -> statlist */\n let fs = ls.fs;\n let bl = new BlockCnt();\n enterblock(fs, bl, 0);\n statlist(ls);\n leaveblock(fs);\n};\n\n/*\n** structure to chain all variables in the left-hand side of an\n** assignment\n*/\nclass LHS_assign {\n constructor() {\n this.prev = null;\n this.v = new expdesc(); /* variable (global, local, upvalue, or indexed) */\n }\n}\n\n/*\n** check whether, in an assignment to an upvalue/local variable, the\n** upvalue/local variable is begin used in a previous assignment to a\n** table. If so, save original upvalue/local value in a safe place and\n** use this safe copy in the previous assignment.\n*/\nconst check_conflict = function(ls, lh, v) {\n let fs = ls.fs;\n let extra = fs.freereg; /* eventual position to save local variable */\n let conflict = false;\n for (; lh; lh = lh.prev) { /* check all previous assignments */\n if (lh.v.k === expkind.VINDEXED) { /* assigning to a table? */\n /* table is the upvalue/local being assigned now? */\n if (lh.v.u.ind.vt === v.k && lh.v.u.ind.t === v.u.info) {\n conflict = true;\n lh.v.u.ind.vt = expkind.VLOCAL;\n lh.v.u.ind.t = extra; /* previous assignment will use safe copy */\n }\n /* index is the local being assigned? (index cannot be upvalue) */\n if (v.k === expkind.VLOCAL && lh.v.u.ind.idx === v.u.info) {\n conflict = true;\n lh.v.u.ind.idx = extra; /* previous assignment will use safe copy */\n }\n }\n }\n if (conflict) {\n /* copy upvalue/local value to a temporary (in position 'extra') */\n let op = v.k === expkind.VLOCAL ? OP_MOVE : OP_GETUPVAL;\n luaK_codeABC(fs, op, extra, v.u.info, 0);\n luaK_reserveregs(fs, 1);\n }\n};\n\nconst assignment = function(ls, lh, nvars) {\n let e = new expdesc();\n check_condition(ls, vkisvar(lh.v.k), to_luastring(\"syntax error\", true));\n if (testnext(ls, 44 /* (',').charCodeAt(0) */)) { /* assignment -> ',' suffixedexp assignment */\n let nv = new LHS_assign();\n nv.prev = lh;\n suffixedexp(ls, nv.v);\n if (nv.v.k !== expkind.VINDEXED)\n check_conflict(ls, lh, nv.v);\n checklimit(ls.fs, nvars + ls.L.nCcalls, LUAI_MAXCCALLS, to_luastring(\"JS levels\", true));\n assignment(ls, nv, nvars + 1);\n } else { /* assignment -> '=' explist */\n checknext(ls, 61 /* ('=').charCodeAt(0) */);\n let nexps = explist(ls, e);\n if (nexps !== nvars)\n adjust_assign(ls, nvars, nexps, e);\n else {\n luaK_setoneret(ls.fs, e); /* close last expression */\n luaK_storevar(ls.fs, lh.v, e);\n return; /* avoid default */\n }\n }\n init_exp(e, expkind.VNONRELOC, ls.fs.freereg-1); /* default assignment */\n luaK_storevar(ls.fs, lh.v, e);\n};\n\nconst cond = function(ls) {\n /* cond -> exp */\n let v = new expdesc();\n expr(ls, v); /* read condition */\n if (v.k === expkind.VNIL) v.k = expkind.VFALSE; /* 'falses' are all equal here */\n luaK_goiftrue(ls.fs, v);\n return v.f;\n};\n\nconst gotostat = function(ls, pc) {\n let line = ls.linenumber;\n let label;\n if (testnext(ls, R.TK_GOTO))\n label = str_checkname(ls);\n else {\n llex.luaX_next(ls); /* skip break */\n label = luaS_newliteral(ls.L, \"break\");\n }\n let g = newlabelentry(ls, ls.dyd.gt, label, line, pc);\n findlabel(ls, g); /* close it if label already defined */\n};\n\n/* check for repeated labels on the same block */\nconst checkrepeated = function(fs, ll, label) {\n for (let i = fs.bl.firstlabel; i < ll.n; i++) {\n if (eqstr(label, ll.arr[i].name)) {\n let msg = lobject.luaO_pushfstring(fs.ls.L,\n to_luastring(\"label '%s' already defined on line %d\", true),\n label.getstr(), ll.arr[i].line);\n semerror(fs.ls, msg);\n }\n }\n};\n\n/* skip no-op statements */\nconst skipnoopstat = function(ls) {\n while (ls.t.token === 59 /* (';').charCodeAt(0) */ || ls.t.token === R.TK_DBCOLON)\n statement(ls);\n};\n\nconst labelstat = function(ls, label, line) {\n /* label -> '::' NAME '::' */\n let fs = ls.fs;\n let ll = ls.dyd.label;\n let l; /* index of new label being created */\n checkrepeated(fs, ll, label); /* check for repeated labels */\n checknext(ls, R.TK_DBCOLON); /* skip double colon */\n /* create new entry for this label */\n l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));\n skipnoopstat(ls); /* skip other no-op statements */\n if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */\n /* assume that locals are already out of scope */\n ll.arr[l].nactvar = fs.bl.nactvar;\n }\n findgotos(ls, ll.arr[l]);\n};\n\nconst whilestat = function(ls, line) {\n /* whilestat -> WHILE cond DO block END */\n let fs = ls.fs;\n let bl = new BlockCnt();\n llex.luaX_next(ls); /* skip WHILE */\n let whileinit = luaK_getlabel(fs);\n let condexit = cond(ls);\n enterblock(fs, bl, 1);\n checknext(ls, R.TK_DO);\n block(ls);\n luaK_jumpto(fs, whileinit);\n check_match(ls, R.TK_END, R.TK_WHILE, line);\n leaveblock(fs);\n luaK_patchtohere(fs, condexit); /* false conditions finish the loop */\n};\n\nconst repeatstat = function(ls, line) {\n /* repeatstat -> REPEAT block UNTIL cond */\n let fs = ls.fs;\n let repeat_init = luaK_getlabel(fs);\n let bl1 = new BlockCnt();\n let bl2 = new BlockCnt();\n enterblock(fs, bl1, 1); /* loop block */\n enterblock(fs, bl2, 0); /* scope block */\n llex.luaX_next(ls); /* skip REPEAT */\n statlist(ls);\n check_match(ls, R.TK_UNTIL, R.TK_REPEAT, line);\n let condexit = cond(ls); /* read condition (inside scope block) */\n if (bl2.upval) /* upvalues? */\n luaK_patchclose(fs, condexit, bl2.nactvar);\n leaveblock(fs); /* finish scope */\n luaK_patchlist(fs, condexit, repeat_init); /* close the loop */\n leaveblock(fs); /* finish loop */\n};\n\nconst exp1 = function(ls) {\n let e = new expdesc();\n expr(ls, e);\n luaK_exp2nextreg(ls.fs, e);\n lua_assert(e.k === expkind.VNONRELOC);\n let reg = e.u.info;\n return reg;\n};\n\nconst forbody = function(ls, base, line, nvars, isnum) {\n /* forbody -> DO block */\n let bl = new BlockCnt();\n let fs = ls.fs;\n let endfor;\n adjustlocalvars(ls, 3); /* control variables */\n checknext(ls, R.TK_DO);\n let prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);\n enterblock(fs, bl, 0); /* scope for declared variables */\n adjustlocalvars(ls, nvars);\n luaK_reserveregs(fs, nvars);\n block(ls);\n leaveblock(fs); /* end of scope for declared variables */\n luaK_patchtohere(fs, prep);\n if (isnum) /* end of scope for declared variables */\n endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP);\n else { /* generic for */\n luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars);\n luaK_fixline(fs, line);\n endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP);\n }\n luaK_patchlist(fs, endfor, prep + 1);\n luaK_fixline(fs, line);\n};\n\nconst fornum = function(ls, varname, line) {\n /* fornum -> NAME = exp1,exp1[,exp1] forbody */\n let fs = ls.fs;\n let base = fs.freereg;\n new_localvarliteral(ls, \"(for index)\");\n new_localvarliteral(ls, \"(for limit)\");\n new_localvarliteral(ls, \"(for step)\");\n new_localvar(ls, varname);\n checknext(ls, 61 /* ('=').charCodeAt(0) */);\n exp1(ls); /* initial value */\n checknext(ls, 44 /* (',').charCodeAt(0) */);\n exp1(ls); /* limit */\n if (testnext(ls, 44 /* (',').charCodeAt(0) */))\n exp1(ls); /* optional step */\n else { /* default step = 1 */\n luaK_codek(fs, fs.freereg, luaK_intK(fs, 1));\n luaK_reserveregs(fs, 1);\n }\n forbody(ls, base, line, 1, 1);\n};\n\nconst forlist = function(ls, indexname) {\n /* forlist -> NAME {,NAME} IN explist forbody */\n let fs = ls.fs;\n let e = new expdesc();\n let nvars = 4; /* gen, state, control, plus at least one declared var */\n let base = fs.freereg;\n /* create control variables */\n new_localvarliteral(ls, \"(for generator)\");\n new_localvarliteral(ls, \"(for state)\");\n new_localvarliteral(ls, \"(for control)\");\n /* create declared variables */\n new_localvar(ls, indexname);\n while (testnext(ls, 44 /* (',').charCodeAt(0) */)) {\n new_localvar(ls, str_checkname(ls));\n nvars++;\n }\n checknext(ls, R.TK_IN);\n let line = ls.linenumber;\n adjust_assign(ls, 3, explist(ls, e), e);\n luaK_checkstack(fs, 3); /* extra space to call generator */\n forbody(ls, base, line, nvars - 3, 0);\n};\n\nconst forstat = function(ls, line) {\n /* forstat -> FOR (fornum | forlist) END */\n let fs = ls.fs;\n let bl = new BlockCnt();\n enterblock(fs, bl, 1); /* scope for loop and control variables */\n llex.luaX_next(ls); /* skip 'for' */\n let varname = str_checkname(ls); /* first variable name */\n switch (ls.t.token) {\n case 61 /* ('=').charCodeAt(0) */: fornum(ls, varname, line); break;\n case 44 /* (',').charCodeAt(0) */: case R.TK_IN: forlist(ls, varname); break;\n default: llex.luaX_syntaxerror(ls, to_luastring(\"'=' or 'in' expected\", true));\n }\n check_match(ls, R.TK_END, R.TK_FOR, line);\n leaveblock(fs); /* loop scope ('break' jumps to this point) */\n};\n\nconst test_then_block = function(ls, escapelist) {\n /* test_then_block -> [IF | ELSEIF] cond THEN block */\n let bl = new BlockCnt();\n let fs = ls.fs;\n let v = new expdesc();\n let jf; /* instruction to skip 'then' code (if condition is false) */\n\n llex.luaX_next(ls); /* skip IF or ELSEIF */\n expr(ls, v); /* read condition */\n checknext(ls, R.TK_THEN);\n\n if (ls.t.token === R.TK_GOTO || ls.t.token === R.TK_BREAK) {\n luaK_goiffalse(ls.fs, v); /* will jump to label if condition is true */\n enterblock(fs, bl, false); /* must enter block before 'goto' */\n gotostat(ls, v.t); /* handle goto/break */\n while (testnext(ls, 59 /* (';').charCodeAt(0) */)); /* skip colons */\n if (block_follow(ls, 0)) { /* 'goto' is the entire block? */\n leaveblock(fs);\n return escapelist; /* and that is it */\n } else /* must skip over 'then' part if condition is false */\n jf = luaK_jump(fs);\n } else { /* regular case (not goto/break) */\n luaK_goiftrue(ls.fs, v); /* skip over block if condition is false */\n enterblock(fs, bl, false);\n jf = v.f;\n }\n\n statlist(ls); /* 'then' part */\n leaveblock(fs);\n if (ls.t.token === R.TK_ELSE || ls.t.token === R.TK_ELSEIF) /* followed by 'else'/'elseif'? */\n escapelist = luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */\n luaK_patchtohere(fs, jf);\n\n return escapelist;\n};\n\nconst ifstat = function(ls, line) {\n /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */\n let fs = ls.fs;\n let escapelist = NO_JUMP; /* exit list for finished parts */\n escapelist = test_then_block(ls, escapelist); /* IF cond THEN block */\n while (ls.t.token === R.TK_ELSEIF)\n escapelist = test_then_block(ls, escapelist); /* ELSEIF cond THEN block */\n if (testnext(ls, R.TK_ELSE))\n block(ls); /* 'else' part */\n check_match(ls, R.TK_END, R.TK_IF, line);\n luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */\n};\n\nconst localfunc = function(ls) {\n let b = new expdesc();\n let fs = ls.fs;\n new_localvar(ls, str_checkname(ls)); /* new local variable */\n adjustlocalvars(ls, 1); /* enter its scope */\n body(ls, b, 0, ls.linenumber); /* function created in next register */\n /* debug information will only see the variable after this point! */\n getlocvar(fs, b.u.info).startpc = fs.pc;\n};\n\nconst localstat = function(ls) {\n /* stat -> LOCAL NAME {',' NAME} ['=' explist] */\n let nvars = 0;\n let nexps;\n let e = new expdesc();\n do {\n new_localvar(ls, str_checkname(ls));\n nvars++;\n } while (testnext(ls, 44 /* (',').charCodeAt(0) */));\n if (testnext(ls, 61 /* ('=').charCodeAt(0) */))\n nexps = explist(ls, e);\n else {\n e.k = expkind.VVOID;\n nexps = 0;\n }\n adjust_assign(ls, nvars, nexps, e);\n adjustlocalvars(ls, nvars);\n};\n\nconst funcname = function(ls, v) {\n /* funcname -> NAME {fieldsel} [':' NAME] */\n let ismethod = 0;\n singlevar(ls, v);\n while (ls.t.token === 46 /* ('.').charCodeAt(0) */)\n fieldsel(ls, v);\n if (ls.t.token === 58 /* (':').charCodeAt(0) */) {\n ismethod = 1;\n fieldsel(ls, v);\n }\n return ismethod;\n};\n\nconst funcstat = function(ls, line) {\n /* funcstat -> FUNCTION funcname body */\n let v = new expdesc();\n let b = new expdesc();\n llex.luaX_next(ls); /* skip FUNCTION */\n let ismethod = funcname(ls, v);\n body(ls, b, ismethod, line);\n luaK_storevar(ls.fs, v, b);\n luaK_fixline(ls.fs, line); /* definition \"happens\" in the first line */\n};\n\nconst exprstat= function(ls) {\n /* stat -> func | assignment */\n let fs = ls.fs;\n let v = new LHS_assign();\n suffixedexp(ls, v.v);\n if (ls.t.token === 61 /* ('=').charCodeAt(0) */ || ls.t.token === 44 /* (',').charCodeAt(0) */) { /* stat . assignment ? */\n v.prev = null;\n assignment(ls, v, 1);\n }\n else { /* stat -> func */\n check_condition(ls, v.v.k === expkind.VCALL, to_luastring(\"syntax error\", true));\n SETARG_C(getinstruction(fs, v.v), 1); /* call statement uses no results */\n }\n};\n\nconst retstat = function(ls) {\n /* stat -> RETURN [explist] [';'] */\n let fs = ls.fs;\n let e = new expdesc();\n let first, nret; /* registers with returned values */\n if (block_follow(ls, 1) || ls.t.token === 59 /* (';').charCodeAt(0) */)\n first = nret = 0; /* return no values */\n else {\n nret = explist(ls, e); /* optional return values */\n if (hasmultret(e.k)) {\n luaK_setmultret(fs, e);\n if (e.k === expkind.VCALL && nret === 1) { /* tail call? */\n SET_OPCODE(getinstruction(fs, e), OP_TAILCALL);\n lua_assert(getinstruction(fs, e).A === fs.nactvar);\n }\n first = fs.nactvar;\n nret = LUA_MULTRET; /* return all values */\n } else {\n if (nret === 1) /* only one single value? */\n first = luaK_exp2anyreg(fs, e);\n else {\n luaK_exp2nextreg(fs, e); /* values must go to the stack */\n first = fs.nactvar; /* return all active values */\n lua_assert(nret === fs.freereg - first);\n }\n }\n }\n luaK_ret(fs, first, nret);\n testnext(ls, 59 /* (';').charCodeAt(0) */); /* skip optional semicolon */\n};\n\nconst statement = function(ls) {\n let line = ls.linenumber; /* may be needed for error messages */\n enterlevel(ls);\n switch(ls.t.token) {\n case 59 /* (';').charCodeAt(0) */: { /* stat -> ';' (empty statement) */\n llex.luaX_next(ls); /* skip ';' */\n break;\n }\n case R.TK_IF: { /* stat -> ifstat */\n ifstat(ls, line);\n break;\n }\n case R.TK_WHILE: { /* stat -> whilestat */\n whilestat(ls, line);\n break;\n }\n case R.TK_DO: { /* stat -> DO block END */\n llex.luaX_next(ls); /* skip DO */\n block(ls);\n check_match(ls, R.TK_END, R.TK_DO, line);\n break;\n }\n case R.TK_FOR: { /* stat -> forstat */\n forstat(ls, line);\n break;\n }\n case R.TK_REPEAT: { /* stat -> repeatstat */\n repeatstat(ls, line);\n break;\n }\n case R.TK_FUNCTION: { /* stat -> funcstat */\n funcstat(ls, line);\n break;\n }\n case R.TK_LOCAL: { /* stat -> localstat */\n llex.luaX_next(ls); /* skip LOCAL */\n if (testnext(ls, R.TK_FUNCTION)) /* local function? */\n localfunc(ls);\n else\n localstat(ls);\n break;\n }\n case R.TK_DBCOLON: { /* stat -> label */\n llex.luaX_next(ls); /* skip double colon */\n labelstat(ls, str_checkname(ls), line);\n break;\n }\n case R.TK_RETURN: { /* skip double colon */\n llex.luaX_next(ls); /* skip RETURN */\n retstat(ls);\n break;\n }\n case R.TK_BREAK: /* stat -> breakstat */\n case R.TK_GOTO: { /* stat -> 'goto' NAME */\n gotostat(ls, luaK_jump(ls.fs));\n break;\n }\n default: { /* stat -> func | assignment */\n exprstat(ls);\n break;\n }\n }\n lua_assert(ls.fs.f.maxstacksize >= ls.fs.freereg && ls.fs.freereg >= ls.fs.nactvar);\n ls.fs.freereg = ls.fs.nactvar; /* free registers */\n leavelevel(ls);\n};\n\n/*\n** compiles the main function, which is a regular vararg function with an\n** upvalue named LUA_ENV\n*/\nconst mainfunc = function(ls, fs) {\n let bl = new BlockCnt();\n let v = new expdesc();\n open_func(ls, fs, bl);\n fs.f.is_vararg = true; /* main function is always declared vararg */\n init_exp(v, expkind.VLOCAL, 0); /* create and... */\n newupvalue(fs, ls.envn, v); /* ...set environment upvalue */\n llex.luaX_next(ls); /* read first token */\n statlist(ls); /* parse main body */\n check(ls, R.TK_EOS);\n close_func(ls);\n};\n\nconst luaY_parser = function(L, z, buff, dyd, name, firstchar) {\n let lexstate = new llex.LexState();\n let funcstate = new FuncState();\n let cl = lfunc.luaF_newLclosure(L, 1); /* create main closure */\n ldo.luaD_inctop(L);\n L.stack[L.top-1].setclLvalue(cl);\n lexstate.h = ltable.luaH_new(L); /* create table for scanner */\n ldo.luaD_inctop(L);\n L.stack[L.top-1].sethvalue(lexstate.h);\n funcstate.f = cl.p = new Proto(L);\n funcstate.f.source = luaS_new(L, name);\n lexstate.buff = buff;\n lexstate.dyd = dyd;\n dyd.actvar.n = dyd.gt.n = dyd.label.n = 0;\n llex.luaX_setinput(L, lexstate, z, funcstate.f.source, firstchar);\n mainfunc(lexstate, funcstate);\n lua_assert(!funcstate.prev && funcstate.nups === 1 && !lexstate.fs);\n /* all scopes should be correctly finished */\n lua_assert(dyd.actvar.n === 0 && dyd.gt.n === 0 && dyd.label.n === 0);\n delete L.stack[--L.top]; /* remove scanner's table */\n return cl; /* closure is on the stack, too */\n};\n\n\nmodule.exports.Dyndata = Dyndata;\nmodule.exports.expkind = expkind;\nmodule.exports.expdesc = expdesc;\nmodule.exports.luaY_parser = luaY_parser;\nmodule.exports.vkisinreg = vkisinreg;\n","\"use strict\";\n\nconst {\n LUA_MULTRET,\n LUA_OK,\n LUA_TFUNCTION,\n LUA_TNIL,\n LUA_TNONE,\n LUA_TNUMBER,\n LUA_TSTRING,\n LUA_TTABLE,\n LUA_VERSION,\n LUA_YIELD,\n lua_call,\n lua_callk,\n lua_concat,\n lua_error,\n lua_getglobal,\n lua_geti,\n lua_getmetatable,\n lua_gettop,\n lua_insert,\n lua_isnil,\n lua_isnone,\n lua_isstring,\n lua_load,\n lua_next,\n lua_pcallk,\n lua_pop,\n lua_pushboolean,\n lua_pushcfunction,\n lua_pushglobaltable,\n lua_pushinteger,\n lua_pushliteral,\n lua_pushnil,\n lua_pushstring,\n lua_pushvalue,\n lua_rawequal,\n lua_rawget,\n lua_rawlen,\n lua_rawset,\n lua_remove,\n lua_replace,\n lua_rotate,\n lua_setfield,\n lua_setmetatable,\n lua_settop,\n lua_setupvalue,\n lua_stringtonumber,\n lua_toboolean,\n lua_tolstring,\n lua_tostring,\n lua_type,\n lua_typename\n} = require('./lua.js');\nconst {\n luaL_argcheck,\n luaL_checkany,\n luaL_checkinteger,\n luaL_checkoption,\n luaL_checkstack,\n luaL_checktype,\n luaL_error,\n luaL_getmetafield,\n luaL_loadbufferx,\n luaL_loadfile,\n luaL_loadfilex,\n luaL_optinteger,\n luaL_optstring,\n luaL_setfuncs,\n luaL_tolstring,\n luaL_where\n} = require('./lauxlib.js');\nconst {\n to_jsstring,\n to_luastring\n} = require(\"./fengaricore.js\");\n\nlet lua_writestring;\nlet lua_writeline;\nif (typeof process === \"undefined\") {\n if (typeof TextDecoder === \"function\") { /* Older browsers don't have TextDecoder */\n let buff = \"\";\n let decoder = new TextDecoder(\"utf-8\");\n lua_writestring = function(s) {\n buff += decoder.decode(s, {stream: true});\n };\n let empty = new Uint8Array(0);\n lua_writeline = function() {\n buff += decoder.decode(empty);\n console.log(buff);\n buff = \"\";\n };\n } else {\n let buff = [];\n lua_writestring = function(s) {\n try {\n /* If the string is valid utf8, then we can use to_jsstring */\n s = to_jsstring(s);\n } catch(e) {\n /* otherwise push copy of raw array */\n let copy = new Uint8Array(s.length);\n copy.set(s);\n s = copy;\n }\n buff.push(s);\n };\n lua_writeline = function() {\n console.log.apply(console.log, buff);\n buff = [];\n };\n }\n} else {\n lua_writestring = function(s) {\n process.stdout.write(Buffer.from(s));\n };\n lua_writeline = function() {\n process.stdout.write(\"\\n\");\n };\n}\nconst luaB_print = function(L) {\n let n = lua_gettop(L); /* number of arguments */\n lua_getglobal(L, to_luastring(\"tostring\", true));\n for (let i = 1; i <= n; i++) {\n lua_pushvalue(L, -1); /* function to be called */\n lua_pushvalue(L, i); /* value to print */\n lua_call(L, 1, 1);\n let s = lua_tolstring(L, -1);\n if (s === null)\n return luaL_error(L, to_luastring(\"'tostring' must return a string to 'print'\"));\n if (i > 1) lua_writestring(to_luastring(\"\\t\"));\n lua_writestring(s);\n lua_pop(L, 1);\n }\n lua_writeline();\n return 0;\n};\n\nconst luaB_tostring = function(L) {\n luaL_checkany(L, 1);\n luaL_tolstring(L, 1);\n\n return 1;\n};\n\nconst luaB_getmetatable = function(L) {\n luaL_checkany(L, 1);\n if (!lua_getmetatable(L, 1)) {\n lua_pushnil(L);\n return 1; /* no metatable */\n }\n luaL_getmetafield(L, 1, to_luastring(\"__metatable\", true));\n return 1; /* returns either __metatable field (if present) or metatable */\n};\n\nconst luaB_setmetatable = function(L) {\n let t = lua_type(L, 2);\n luaL_checktype(L, 1, LUA_TTABLE);\n luaL_argcheck(L, t === LUA_TNIL || t === LUA_TTABLE, 2, \"nil or table expected\");\n if (luaL_getmetafield(L, 1, to_luastring(\"__metatable\", true)) !== LUA_TNIL)\n return luaL_error(L, to_luastring(\"cannot change a protected metatable\"));\n lua_settop(L, 2);\n lua_setmetatable(L, 1);\n return 1;\n};\n\nconst luaB_rawequal = function(L) {\n luaL_checkany(L, 1);\n luaL_checkany(L, 2);\n lua_pushboolean(L, lua_rawequal(L, 1, 2));\n return 1;\n};\n\nconst luaB_rawlen = function(L) {\n let t = lua_type(L, 1);\n luaL_argcheck(L, t === LUA_TTABLE || t === LUA_TSTRING, 1, \"table or string expected\");\n lua_pushinteger(L, lua_rawlen(L, 1));\n return 1;\n};\n\nconst luaB_rawget = function(L) {\n luaL_checktype(L, 1, LUA_TTABLE);\n luaL_checkany(L, 2);\n lua_settop(L, 2);\n lua_rawget(L, 1);\n return 1;\n};\n\nconst luaB_rawset = function(L) {\n luaL_checktype(L, 1, LUA_TTABLE);\n luaL_checkany(L, 2);\n luaL_checkany(L, 3);\n lua_settop(L, 3);\n lua_rawset(L, 1);\n return 1;\n};\n\nconst opts = [\n \"stop\", \"restart\", \"collect\",\n \"count\", \"step\", \"setpause\", \"setstepmul\",\n \"isrunning\"\n].map((e) => to_luastring(e));\nconst luaB_collectgarbage = function(L) {\n luaL_checkoption(L, 1, \"collect\", opts);\n luaL_optinteger(L, 2, 0);\n luaL_error(L, to_luastring(\"lua_gc not implemented\"));\n};\n\nconst luaB_type = function(L) {\n let t = lua_type(L, 1);\n luaL_argcheck(L, t !== LUA_TNONE, 1, \"value expected\");\n lua_pushstring(L, lua_typename(L, t));\n return 1;\n};\n\nconst pairsmeta = function(L, method, iszero, iter) {\n luaL_checkany(L, 1);\n if (luaL_getmetafield(L, 1, method) === LUA_TNIL) { /* no metamethod? */\n lua_pushcfunction(L, iter); /* will return generator, */\n lua_pushvalue(L, 1); /* state, */\n if (iszero) lua_pushinteger(L, 0); /* and initial value */\n else lua_pushnil(L);\n } else {\n lua_pushvalue(L, 1); /* argument 'self' to metamethod */\n lua_call(L, 1, 3); /* get 3 values from metamethod */\n }\n return 3;\n};\n\nconst luaB_next = function(L) {\n luaL_checktype(L, 1, LUA_TTABLE);\n lua_settop(L, 2); /* create a 2nd argument if there isn't one */\n if (lua_next(L, 1))\n return 2;\n else {\n lua_pushnil(L);\n return 1;\n }\n};\n\nconst luaB_pairs = function(L) {\n return pairsmeta(L, to_luastring(\"__pairs\", true), 0, luaB_next);\n};\n\n/*\n** Traversal function for 'ipairs'\n*/\nconst ipairsaux = function(L) {\n let i = luaL_checkinteger(L, 2) + 1;\n lua_pushinteger(L, i);\n return lua_geti(L, 1, i) === LUA_TNIL ? 1 : 2;\n};\n\n/*\n** 'ipairs' function. Returns 'ipairsaux', given \"table\", 0.\n** (The given \"table\" may not be a table.)\n*/\nconst luaB_ipairs = function(L) {\n // Lua 5.2\n // return pairsmeta(L, \"__ipairs\", 1, ipairsaux);\n\n luaL_checkany(L, 1);\n lua_pushcfunction(L, ipairsaux); /* iteration function */\n lua_pushvalue(L, 1); /* state */\n lua_pushinteger(L, 0); /* initial value */\n return 3;\n};\n\nconst b_str2int = function(s, base) {\n try {\n s = to_jsstring(s);\n } catch (e) {\n return null;\n }\n let r = /^[\\t\\v\\f \\n\\r]*([+-]?)0*([0-9A-Za-z]+)[\\t\\v\\f \\n\\r]*$/.exec(s);\n if (!r) return null;\n let v = parseInt(r[1]+r[2], base);\n if (isNaN(v)) return null;\n return v|0;\n};\n\nconst luaB_tonumber = function(L) {\n if (lua_type(L, 2) <= 0) { /* standard conversion? */\n luaL_checkany(L, 1);\n if (lua_type(L, 1) === LUA_TNUMBER) { /* already a number? */\n lua_settop(L, 1);\n return 1;\n } else {\n let s = lua_tostring(L, 1);\n if (s !== null && lua_stringtonumber(L, s) === s.length+1)\n return 1; /* successful conversion to number */\n }\n } else {\n let base = luaL_checkinteger(L, 2);\n luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */\n let s = lua_tostring(L, 1);\n luaL_argcheck(L, 2 <= base && base <= 36, 2, \"base out of range\");\n let n = b_str2int(s, base);\n if (n !== null) {\n lua_pushinteger(L, n);\n return 1;\n }\n }\n\n lua_pushnil(L);\n return 1;\n};\n\nconst luaB_error = function(L) {\n let level = luaL_optinteger(L, 2, 1);\n lua_settop(L, 1);\n if (lua_type(L, 1) === LUA_TSTRING && level > 0) {\n luaL_where(L, level); /* add extra information */\n lua_pushvalue(L, 1);\n lua_concat(L, 2);\n }\n return lua_error(L);\n};\n\nconst luaB_assert = function(L) {\n if (lua_toboolean(L, 1)) /* condition is true? */\n return lua_gettop(L); /* return all arguments */\n else {\n luaL_checkany(L, 1); /* there must be a condition */\n lua_remove(L, 1); /* remove it */\n lua_pushliteral(L, \"assertion failed!\"); /* default message */\n lua_settop(L, 1); /* leave only message (default if no other one) */\n return luaB_error(L); /* call 'error' */\n }\n};\n\nconst luaB_select = function(L) {\n let n = lua_gettop(L);\n if (lua_type(L, 1) === LUA_TSTRING && lua_tostring(L, 1)[0] === 35 /* '#'.charCodeAt(0) */) {\n lua_pushinteger(L, n - 1);\n return 1;\n } else {\n let i = luaL_checkinteger(L, 1);\n if (i < 0) i = n + i;\n else if (i > n) i = n;\n luaL_argcheck(L, 1 <= i, 1, \"index out of range\");\n return n - i;\n }\n};\n\n/*\n** Continuation function for 'pcall' and 'xpcall'. Both functions\n** already pushed a 'true' before doing the call, so in case of success\n** 'finishpcall' only has to return everything in the stack minus\n** 'extra' values (where 'extra' is exactly the number of items to be\n** ignored).\n*/\nconst finishpcall = function(L, status, extra) {\n if (status !== LUA_OK && status !== LUA_YIELD) { /* error? */\n lua_pushboolean(L, 0); /* first result (false) */\n lua_pushvalue(L, -2); /* error message */\n return 2; /* return false, msg */\n } else\n return lua_gettop(L) - extra;\n};\n\nconst luaB_pcall = function(L) {\n luaL_checkany(L, 1);\n lua_pushboolean(L, 1); /* first result if no errors */\n lua_insert(L, 1); /* put it in place */\n let status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall);\n return finishpcall(L, status, 0);\n};\n\n/*\n** Do a protected call with error handling. After 'lua_rotate', the\n** stack will have ; so, the function passes\n** 2 to 'finishpcall' to skip the 2 first values when returning results.\n*/\nconst luaB_xpcall = function(L) {\n let n = lua_gettop(L);\n luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */\n lua_pushboolean(L, 1); /* first result */\n lua_pushvalue(L, 1); /* function */\n lua_rotate(L, 3, 2); /* move them below function's arguments */\n let status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall);\n return finishpcall(L, status, 2);\n};\n\nconst load_aux = function(L, status, envidx) {\n if (status === LUA_OK) {\n if (envidx !== 0) { /* 'env' parameter? */\n lua_pushvalue(L, envidx); /* environment for loaded function */\n if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */\n lua_pop(L, 1); /* remove 'env' if not used by previous call */\n }\n return 1;\n } else { /* error (message is on top of the stack) */\n lua_pushnil(L);\n lua_insert(L, -2); /* put before error message */\n return 2; /* return nil plus error message */\n }\n};\n\n/*\n** reserved slot, above all arguments, to hold a copy of the returned\n** string to avoid it being collected while parsed. 'load' has four\n** optional arguments (chunk, source name, mode, and environment).\n*/\nconst RESERVEDSLOT = 5;\n\n/*\n** Reader for generic 'load' function: 'lua_load' uses the\n** stack for internal stuff, so the reader cannot change the\n** stack top. Instead, it keeps its resulting string in a\n** reserved slot inside the stack.\n*/\nconst generic_reader = function(L, ud) {\n luaL_checkstack(L, 2, \"too many nested functions\");\n lua_pushvalue(L, 1); /* get function */\n lua_call(L, 0, 1); /* call it */\n if (lua_isnil(L, -1)) {\n lua_pop(L, 1); /* pop result */\n return null;\n } else if (!lua_isstring(L, -1))\n luaL_error(L, to_luastring(\"reader function must return a string\"));\n lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */\n return lua_tostring(L, RESERVEDSLOT);\n};\n\nconst luaB_load = function(L) {\n let s = lua_tostring(L, 1);\n let mode = luaL_optstring(L, 3, \"bt\");\n let env = !lua_isnone(L, 4) ? 4 : 0; /* 'env' index or 0 if no 'env' */\n let status;\n if (s !== null) { /* loading a string? */\n let chunkname = luaL_optstring(L, 2, s);\n status = luaL_loadbufferx(L, s, s.length, chunkname, mode);\n } else { /* loading from a reader function */\n let chunkname = luaL_optstring(L, 2, \"=(load)\");\n luaL_checktype(L, 1, LUA_TFUNCTION);\n lua_settop(L, RESERVEDSLOT); /* create reserved slot */\n status = lua_load(L, generic_reader, null, chunkname, mode);\n }\n return load_aux(L, status, env);\n};\n\nconst luaB_loadfile = function(L) {\n let fname = luaL_optstring(L, 1, null);\n let mode = luaL_optstring(L, 2, null);\n let env = !lua_isnone(L, 3) ? 3 : 0; /* 'env' index or 0 if no 'env' */\n let status = luaL_loadfilex(L, fname, mode);\n return load_aux(L, status, env);\n};\n\nconst dofilecont = function(L, d1, d2) {\n return lua_gettop(L) - 1;\n};\n\nconst luaB_dofile = function(L) {\n let fname = luaL_optstring(L, 1, null);\n lua_settop(L, 1);\n if (luaL_loadfile(L, fname) !== LUA_OK)\n return lua_error(L);\n lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);\n return dofilecont(L, 0, 0);\n};\n\nconst base_funcs = {\n \"assert\": luaB_assert,\n \"collectgarbage\": luaB_collectgarbage,\n \"dofile\": luaB_dofile,\n \"error\": luaB_error,\n \"getmetatable\": luaB_getmetatable,\n \"ipairs\": luaB_ipairs,\n \"load\": luaB_load,\n \"loadfile\": luaB_loadfile,\n \"next\": luaB_next,\n \"pairs\": luaB_pairs,\n \"pcall\": luaB_pcall,\n \"print\": luaB_print,\n \"rawequal\": luaB_rawequal,\n \"rawget\": luaB_rawget,\n \"rawlen\": luaB_rawlen,\n \"rawset\": luaB_rawset,\n \"select\": luaB_select,\n \"setmetatable\": luaB_setmetatable,\n \"tonumber\": luaB_tonumber,\n \"tostring\": luaB_tostring,\n \"type\": luaB_type,\n \"xpcall\": luaB_xpcall\n};\n\nconst luaopen_base = function(L) {\n /* open lib into global table */\n lua_pushglobaltable(L);\n luaL_setfuncs(L, base_funcs, 0);\n /* set global _G */\n lua_pushvalue(L, -1);\n lua_setfield(L, -2, to_luastring(\"_G\"));\n /* set global _VERSION */\n lua_pushliteral(L, LUA_VERSION);\n lua_setfield(L, -2, to_luastring(\"_VERSION\"));\n return 1;\n};\n\nmodule.exports.luaopen_base = luaopen_base;\n","\"use strict\";\n\nconst {\n LUA_OK,\n LUA_TFUNCTION,\n LUA_TSTRING,\n LUA_YIELD,\n lua_Debug,\n lua_checkstack,\n lua_concat,\n lua_error,\n lua_getstack,\n lua_gettop,\n lua_insert,\n lua_isyieldable,\n lua_newthread,\n lua_pop,\n lua_pushboolean,\n lua_pushcclosure,\n lua_pushliteral,\n lua_pushthread,\n lua_pushvalue,\n lua_resume,\n lua_status,\n lua_tothread,\n lua_type,\n lua_upvalueindex,\n lua_xmove,\n lua_yield\n} = require('./lua.js');\nconst {\n luaL_argcheck,\n luaL_checktype,\n luaL_newlib,\n luaL_where\n} = require('./lauxlib.js');\n\nconst getco = function(L) {\n let co = lua_tothread(L, 1);\n luaL_argcheck(L, co, 1, \"thread expected\");\n return co;\n};\n\nconst auxresume = function(L, co, narg) {\n if (!lua_checkstack(co, narg)) {\n lua_pushliteral(L, \"too many arguments to resume\");\n return -1; /* error flag */\n }\n\n if (lua_status(co) === LUA_OK && lua_gettop(co) === 0) {\n lua_pushliteral(L, \"cannot resume dead coroutine\");\n return -1; /* error flag */\n }\n\n lua_xmove(L, co, narg);\n let status = lua_resume(co, L, narg);\n if (status === LUA_OK || status === LUA_YIELD) {\n let nres = lua_gettop(co);\n if (!lua_checkstack(L, nres + 1)) {\n lua_pop(co, nres); /* remove results anyway */\n lua_pushliteral(L, \"too many results to resume\");\n return -1; /* error flag */\n }\n\n lua_xmove(co, L, nres); /* move yielded values */\n return nres;\n } else {\n lua_xmove(co, L, 1); /* move error message */\n return -1; /* error flag */\n }\n};\n\nconst luaB_coresume = function(L) {\n let co = getco(L);\n let r = auxresume(L, co, lua_gettop(L) - 1);\n if (r < 0) {\n lua_pushboolean(L, 0);\n lua_insert(L, -2);\n return 2; /* return false + error message */\n } else {\n lua_pushboolean(L, 1);\n lua_insert(L, -(r + 1));\n return r + 1; /* return true + 'resume' returns */\n }\n};\n\nconst luaB_auxwrap = function(L) {\n let co = lua_tothread(L, lua_upvalueindex(1));\n let r = auxresume(L, co, lua_gettop(L));\n if (r < 0) {\n if (lua_type(L, -1) === LUA_TSTRING) { /* error object is a string? */\n luaL_where(L, 1); /* add extra info */\n lua_insert(L, -2);\n lua_concat(L, 2);\n }\n\n return lua_error(L); /* propagate error */\n }\n\n return r;\n};\n\nconst luaB_cocreate = function(L) {\n luaL_checktype(L, 1, LUA_TFUNCTION);\n let NL = lua_newthread(L);\n lua_pushvalue(L, 1); /* move function to top */\n lua_xmove(L, NL, 1); /* move function from L to NL */\n return 1;\n};\n\nconst luaB_cowrap = function(L) {\n luaB_cocreate(L);\n lua_pushcclosure(L, luaB_auxwrap, 1);\n return 1;\n};\n\nconst luaB_yield = function(L) {\n return lua_yield(L, lua_gettop(L));\n};\n\nconst luaB_costatus = function(L) {\n let co = getco(L);\n if (L === co) lua_pushliteral(L, \"running\");\n else {\n switch (lua_status(co)) {\n case LUA_YIELD:\n lua_pushliteral(L, \"suspended\");\n break;\n case LUA_OK: {\n let ar = new lua_Debug();\n if (lua_getstack(co, 0, ar) > 0) /* does it have frames? */\n lua_pushliteral(L, \"normal\"); /* it is running */\n else if (lua_gettop(co) === 0)\n lua_pushliteral(L, \"dead\");\n else\n lua_pushliteral(L, \"suspended\"); /* initial state */\n break;\n }\n default: /* some error occurred */\n lua_pushliteral(L, \"dead\");\n break;\n }\n }\n\n return 1;\n};\n\nconst luaB_yieldable = function(L) {\n lua_pushboolean(L, lua_isyieldable(L));\n return 1;\n};\n\nconst luaB_corunning = function(L) {\n lua_pushboolean(L, lua_pushthread(L));\n return 2;\n};\n\nconst co_funcs = {\n \"create\": luaB_cocreate,\n \"isyieldable\": luaB_yieldable,\n \"resume\": luaB_coresume,\n \"running\": luaB_corunning,\n \"status\": luaB_costatus,\n \"wrap\": luaB_cowrap,\n \"yield\": luaB_yield\n};\n\nconst luaopen_coroutine = function(L) {\n luaL_newlib(L, co_funcs);\n return 1;\n};\n\nmodule.exports.luaopen_coroutine = luaopen_coroutine;\n","\"use strict\";\n\nconst { LUA_MAXINTEGER } = require('./luaconf.js');\nconst {\n LUA_OPEQ,\n LUA_OPLT,\n LUA_TFUNCTION,\n LUA_TNIL,\n LUA_TTABLE,\n lua_call,\n lua_checkstack,\n lua_compare,\n lua_createtable,\n lua_geti,\n lua_getmetatable,\n lua_gettop,\n lua_insert,\n lua_isnil,\n lua_isnoneornil,\n lua_isstring,\n lua_pop,\n lua_pushinteger,\n lua_pushnil,\n lua_pushstring,\n lua_pushvalue,\n lua_rawget,\n lua_setfield,\n lua_seti,\n lua_settop,\n lua_toboolean,\n lua_type\n} = require('./lua.js');\nconst {\n luaL_Buffer,\n luaL_addlstring,\n luaL_addvalue,\n luaL_argcheck,\n luaL_buffinit,\n luaL_checkinteger,\n luaL_checktype,\n luaL_error,\n luaL_len,\n luaL_newlib,\n luaL_opt,\n luaL_optinteger,\n luaL_optlstring,\n luaL_pushresult,\n luaL_typename\n} = require('./lauxlib.js');\nconst lualib = require('./lualib.js');\nconst { to_luastring } = require(\"./fengaricore.js\");\n\n/*\n** Operations that an object must define to mimic a table\n** (some functions only need some of them)\n*/\nconst TAB_R = 1; /* read */\nconst TAB_W = 2; /* write */\nconst TAB_L = 4; /* length */\nconst TAB_RW = (TAB_R | TAB_W); /* read/write */\n\nconst checkfield = function(L, key, n) {\n lua_pushstring(L, key);\n return lua_rawget(L, -n) !== LUA_TNIL;\n};\n\n/*\n** Check that 'arg' either is a table or can behave like one (that is,\n** has a metatable with the required metamethods)\n*/\nconst checktab = function(L, arg, what) {\n if (lua_type(L, arg) !== LUA_TTABLE) { /* is it not a table? */\n let n = 1;\n if (lua_getmetatable(L, arg) && /* must have metatable */\n (!(what & TAB_R) || checkfield(L, to_luastring(\"__index\", true), ++n)) &&\n (!(what & TAB_W) || checkfield(L, to_luastring(\"__newindex\", true), ++n)) &&\n (!(what & TAB_L) || checkfield(L, to_luastring(\"__len\", true), ++n))) {\n lua_pop(L, n); /* pop metatable and tested metamethods */\n }\n else\n luaL_checktype(L, arg, LUA_TTABLE); /* force an error */\n }\n};\n\nconst aux_getn = function(L, n, w) {\n checktab(L, n, w | TAB_L);\n return luaL_len(L, n);\n};\n\nconst addfield = function(L, b, i) {\n lua_geti(L, 1, i);\n if (!lua_isstring(L, -1))\n luaL_error(L, to_luastring(\"invalid value (%s) at index %d in table for 'concat'\"),\n luaL_typename(L, -1), i);\n\n luaL_addvalue(b);\n};\n\nconst tinsert = function(L) {\n let e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */\n let pos;\n switch (lua_gettop(L)) {\n case 2:\n pos = e;\n break;\n case 3: {\n pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */\n luaL_argcheck(L, 1 <= pos && pos <= e, 2, \"position out of bounds\");\n for (let i = e; i > pos; i--) { /* move up elements */\n lua_geti(L, 1, i - 1);\n lua_seti(L, 1, i); /* t[i] = t[i - 1] */\n }\n break;\n }\n default: {\n return luaL_error(L, \"wrong number of arguments to 'insert'\");\n }\n }\n\n lua_seti(L, 1, pos); /* t[pos] = v */\n return 0;\n};\n\nconst tremove = function(L) {\n let size = aux_getn(L, 1, TAB_RW);\n let pos = luaL_optinteger(L, 2, size);\n if (pos !== size) /* validate 'pos' if given */\n luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, \"position out of bounds\");\n lua_geti(L, 1, pos); /* result = t[pos] */\n for (; pos < size; pos++) {\n lua_geti(L, 1, pos + 1);\n lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */\n }\n lua_pushnil(L);\n lua_seti(L, 1, pos); /* t[pos] = nil */\n return 1;\n};\n\n/*\n** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever\n** possible, copy in increasing order, which is better for rehashing.\n** \"possible\" means destination after original range, or smaller\n** than origin, or copying to another table.\n*/\nconst tmove = function(L) {\n let f = luaL_checkinteger(L, 2);\n let e = luaL_checkinteger(L, 3);\n let t = luaL_checkinteger(L, 4);\n let tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */\n checktab(L, 1, TAB_R);\n checktab(L, tt, TAB_W);\n if (e >= f) { /* otherwise, nothing to move */\n luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, \"too many elements to move\");\n let n = e - f + 1; /* number of elements to move */\n luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, \"destination wrap around\");\n\n if (t > e || t <= f || (tt !== 1 && lua_compare(L, 1, tt, LUA_OPEQ) !== 1)) {\n for (let i = 0; i < n; i++) {\n lua_geti(L, 1, f + i);\n lua_seti(L, tt, t + i);\n }\n } else {\n for (let i = n - 1; i >= 0; i--) {\n lua_geti(L, 1, f + i);\n lua_seti(L, tt, t + i);\n }\n }\n }\n\n lua_pushvalue(L, tt); /* return destination table */\n return 1;\n};\n\nconst tconcat = function(L) {\n let last = aux_getn(L, 1, TAB_R);\n let sep = luaL_optlstring(L, 2, \"\");\n let lsep = sep.length;\n let i = luaL_optinteger(L, 3, 1);\n last = luaL_optinteger(L, 4, last);\n\n let b = new luaL_Buffer();\n luaL_buffinit(L, b);\n\n for (; i < last; i++) {\n addfield(L, b, i);\n luaL_addlstring(b, sep, lsep);\n }\n\n if (i === last)\n addfield(L, b, i);\n\n luaL_pushresult(b);\n\n return 1;\n};\n\nconst pack = function(L) {\n let n = lua_gettop(L); /* number of elements to pack */\n lua_createtable(L, n, 1); /* create result table */\n lua_insert(L, 1); /* put it at index 1 */\n for (let i = n; i >= 1; i--) /* assign elements */\n lua_seti(L, 1, i);\n lua_pushinteger(L, n);\n lua_setfield(L, 1, to_luastring(\"n\")); /* t.n = number of elements */\n return 1; /* return table */\n};\n\nconst unpack = function(L) {\n let i = luaL_optinteger(L, 2, 1);\n let e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));\n if (i > e) return 0; /* empty range */\n let n = e - i; /* number of elements minus 1 (avoid overflows) */\n if (n >= Number.MAX_SAFE_INTEGER || !lua_checkstack(L, ++n))\n return luaL_error(L, to_luastring(\"too many results to unpack\"));\n for (; i < e; i++) /* push arg[i..e - 1] (to avoid overflows) */\n lua_geti(L, 1, i);\n lua_geti(L, 1, e); /* push last element */\n return n;\n};\n\nconst l_randomizePivot = function() {\n return Math.floor(Math.random()*0x100000000);\n};\n\nconst RANLIMIT = 100;\n\nconst set2 = function(L, i, j) {\n lua_seti(L, 1, i);\n lua_seti(L, 1, j);\n};\n\nconst sort_comp = function(L, a, b) {\n if (lua_isnil(L, 2)) /* no function? */\n return lua_compare(L, a, b, LUA_OPLT); /* a < b */\n else { /* function */\n lua_pushvalue(L, 2); /* push function */\n lua_pushvalue(L, a-1); /* -1 to compensate function */\n lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */\n lua_call(L, 2, 1); /* call function */\n let res = lua_toboolean(L, -1); /* get result */\n lua_pop(L, 1); /* pop result */\n return res;\n }\n};\n\nconst partition = function(L, lo, up) {\n let i = lo; /* will be incremented before first use */\n let j = up - 1; /* will be decremented before first use */\n /* loop invariant: a[lo .. i] <= P <= a[j .. up] */\n for (;;) {\n /* next loop: repeat ++i while a[i] < P */\n while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {\n if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */\n luaL_error(L, to_luastring(\"invalid order function for sorting\"));\n lua_pop(L, 1); /* remove a[i] */\n }\n /* after the loop, a[i] >= P and a[lo .. i - 1] < P */\n /* next loop: repeat --j while P < a[j] */\n while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {\n if (j < i) /* j < i but a[j] > P ?? */\n luaL_error(L, to_luastring(\"invalid order function for sorting\"));\n lua_pop(L, 1); /* remove a[j] */\n }\n /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */\n if (j < i) { /* no elements out of place? */\n /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */\n lua_pop(L, 1); /* pop a[j] */\n /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */\n set2(L, up - 1, i);\n return i;\n }\n /* otherwise, swap a[i] - a[j] to restore invariant and repeat */\n set2(L, i, j);\n }\n};\n\nconst choosePivot = function(lo, up, rnd) {\n let r4 = Math.floor((up - lo) / 4); /* range/4 */\n let p = rnd % (r4 * 2) + (lo + r4);\n lualib.lua_assert(lo + r4 <= p && p <= up - r4);\n return p;\n};\n\nconst auxsort = function(L, lo, up, rnd) {\n while (lo < up) { /* loop for tail recursion */\n /* sort elements 'lo', 'p', and 'up' */\n lua_geti(L, 1, lo);\n lua_geti(L, 1, up);\n if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */\n set2(L, lo, up); /* swap a[lo] - a[up] */\n else\n lua_pop(L, 2); /* remove both values */\n if (up - lo == 1) /* only 2 elements? */\n return; /* already sorted */\n let p; /* Pivot index */\n if (up - lo < RANLIMIT || rnd === 0) /* small interval or no randomize? */\n p = Math.floor((lo + up)/2); /* middle element is a good pivot */\n else /* for larger intervals, it is worth a random pivot */\n p = choosePivot(lo, up, rnd);\n lua_geti(L, 1, p);\n lua_geti(L, 1, lo);\n if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */\n set2(L, p, lo); /* swap a[p] - a[lo] */\n else {\n lua_pop(L, 1); /* remove a[lo] */\n lua_geti(L, 1, up);\n if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */\n set2(L, p, up); /* swap a[up] - a[p] */\n else\n lua_pop(L, 2);\n }\n if (up - lo == 2) /* only 3 elements? */\n return; /* already sorted */\n lua_geti(L, 1, p); /* get middle element (Pivot) */\n lua_pushvalue(L, -1); /* push Pivot */\n lua_geti(L, 1, up - 1); /* push a[up - 1] */\n set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */\n p = partition(L, lo, up);\n let n;\n /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */\n if (p - lo < up - p) { /* lower interval is smaller? */\n auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */\n n = p - lo; /* size of smaller interval */\n lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */\n } else {\n auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */\n n = up - p; /* size of smaller interval */\n up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */\n }\n if ((up - lo) / 128 > n) /* partition too imbalanced? */\n rnd = l_randomizePivot(); /* try a new randomization */\n } /* tail call auxsort(L, lo, up, rnd) */\n};\n\nconst sort = function(L) {\n let n = aux_getn(L, 1, TAB_RW);\n if (n > 1) { /* non-trivial interval? */\n luaL_argcheck(L, n < LUA_MAXINTEGER, 1, \"array too big\");\n if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */\n luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */\n lua_settop(L, 2); /* make sure there are two arguments */\n auxsort(L, 1, n, 0);\n }\n return 0;\n};\n\nconst tab_funcs = {\n \"concat\": tconcat,\n \"insert\": tinsert,\n \"move\": tmove,\n \"pack\": pack,\n \"remove\": tremove,\n \"sort\": sort,\n \"unpack\": unpack\n};\n\nconst luaopen_table = function(L) {\n luaL_newlib(L, tab_funcs);\n return 1;\n};\n\nmodule.exports.luaopen_table = luaopen_table;\n","\"use strict\";\n\nconst {\n LUA_TNIL,\n LUA_TTABLE,\n lua_close,\n lua_createtable,\n lua_getfield,\n lua_isboolean,\n lua_isnoneornil,\n lua_pop,\n lua_pushboolean,\n lua_pushfstring,\n lua_pushinteger,\n lua_pushliteral,\n lua_pushnil,\n lua_pushnumber,\n lua_pushstring,\n lua_setfield,\n lua_settop,\n lua_toboolean,\n lua_tointegerx\n} = require('./lua.js');\nconst {\n luaL_Buffer,\n luaL_addchar,\n luaL_addstring,\n // luaL_argcheck,\n luaL_argerror,\n luaL_buffinit,\n luaL_checkinteger,\n luaL_checkstring,\n luaL_checktype,\n luaL_error,\n luaL_execresult,\n luaL_fileresult,\n luaL_newlib,\n luaL_optinteger,\n luaL_optlstring,\n luaL_optstring,\n luaL_pushresult\n} = require('./lauxlib.js');\nconst {\n luastring_eq,\n to_jsstring,\n to_luastring\n} = require(\"./fengaricore.js\");\n\n/* options for ANSI C 89 (only 1-char options) */\n// const L_STRFTIMEC89 = to_luastring(\"aAbBcdHIjmMpSUwWxXyYZ%\");\n// const LUA_STRFTIMEOPTIONS = L_STRFTIMEC89;\n\n/* options for ISO C 99 and POSIX */\n// const L_STRFTIMEC99 = to_luastring(\"aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%||EcECExEXEyEYOdOeOHOIOmOMOSOuOUOVOwOWOy\"); /* two-char options */\n// const LUA_STRFTIMEOPTIONS = L_STRFTIMEC99;\n\n/* options for Windows */\n// const L_STRFTIMEWIN = to_luastring(\"aAbBcdHIjmMpSUwWxXyYzZ%||#c#x#d#H#I#j#m#M#S#U#w#W#y#Y\"); /* two-char options */\n// const LUA_STRFTIMEOPTIONS = L_STRFTIMEWIN;\n\n/* options for our own strftime implementation\n - should be superset of C89 options for compat\n - missing from C99:\n - ISO 8601 week specifiers: gGV\n - > single char specifiers\n - beyond C99:\n - %k: TZ extension: space-padded 24-hour\n - %l: TZ extension: space-padded 12-hour\n - %P: GNU extension: lower-case am/pm\n*/\nconst LUA_STRFTIMEOPTIONS = to_luastring(\"aAbBcCdDeFhHIjklmMnpPrRStTuUwWxXyYzZ%\");\n\n\nconst setfield = function(L, key, value) {\n lua_pushinteger(L, value);\n lua_setfield(L, -2, to_luastring(key, true));\n};\n\nconst setallfields = function(L, time, utc) {\n setfield(L, \"sec\", utc ? time.getUTCSeconds() : time.getSeconds());\n setfield(L, \"min\", utc ? time.getUTCMinutes() : time.getMinutes());\n setfield(L, \"hour\", utc ? time.getUTCHours() : time.getHours());\n setfield(L, \"day\", utc ? time.getUTCDate() : time.getDate());\n setfield(L, \"month\", (utc ? time.getUTCMonth() : time.getMonth()) + 1);\n setfield(L, \"year\", utc ? time.getUTCFullYear() : time.getFullYear());\n setfield(L, \"wday\", (utc ? time.getUTCDay() : time.getDay()) + 1);\n setfield(L, \"yday\", Math.floor((time - (new Date(time.getFullYear(), 0, 0 /* shortcut to correct day by one */))) / 86400000));\n // setboolfield(L, \"isdst\", time.get);\n};\n\nconst L_MAXDATEFIELD = (Number.MAX_SAFE_INTEGER / 2);\n\nconst getfield = function(L, key, d, delta) {\n let t = lua_getfield(L, -1, to_luastring(key, true)); /* get field and its type */\n let res = lua_tointegerx(L, -1);\n if (res === false) { /* field is not an integer? */\n if (t !== LUA_TNIL) /* some other value? */\n return luaL_error(L, to_luastring(\"field '%s' is not an integer\"), key);\n else if (d < 0) /* absent field; no default? */\n return luaL_error(L, to_luastring(\"field '%s' missing in date table\"), key);\n res = d;\n }\n else {\n if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))\n return luaL_error(L, to_luastring(\"field '%s' is out-of-bound\"), key);\n res -= delta;\n }\n lua_pop(L, 1);\n return res;\n};\n\n\nconst locale = {\n days: [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\" ].map((s) => to_luastring(s)),\n shortDays: [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"].map((s) => to_luastring(s)),\n months: [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"].map((s) => to_luastring(s)),\n shortMonths: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"].map((s) => to_luastring(s)),\n AM: to_luastring(\"AM\"),\n PM: to_luastring(\"PM\"),\n am: to_luastring(\"am\"),\n pm: to_luastring(\"pm\"),\n formats: {\n c: to_luastring(\"%a %b %e %H:%M:%S %Y\"),\n D: to_luastring(\"%m/%d/%y\"),\n F: to_luastring(\"%Y-%m-%d\"),\n R: to_luastring(\"%H:%M\"),\n r: to_luastring(\"%I:%M:%S %p\"),\n T: to_luastring(\"%H:%M:%S\"),\n X: to_luastring(\"%T\"),\n x: to_luastring(\"%D\")\n }\n};\n\nconst week_number = function(date, start_of_week) {\n // This works by shifting the weekday back by one day if we\n // are treating Monday as the first day of the week.\n let weekday = date.getDay();\n if (start_of_week === 'monday') {\n if (weekday === 0) // Sunday\n weekday = 6;\n else\n weekday--;\n }\n let yday = (date - new Date(date.getFullYear(), 0, 1)) / 86400000;\n return Math.floor((yday + 7 - weekday) / 7);\n};\n\nconst push_pad_2 = function(b, n, pad) {\n if (n < 10)\n luaL_addchar(b, pad);\n luaL_addstring(b, to_luastring(String(n)));\n};\n\nconst strftime = function(L, b, s, date) {\n let i = 0;\n while (i < s.length) {\n if (s[i] !== 37 /* % */) { /* not a conversion specifier? */\n luaL_addchar(b, s[i++]);\n } else {\n i++; /* skip '%' */\n let len = checkoption(L, s, i);\n /* each `case` has an example output above it for the UTC epoch */\n switch(s[i]) {\n // '%'\n case 37 /* % */:\n luaL_addchar(b, 37);\n break;\n\n // 'Thursday'\n case 65 /* A */:\n luaL_addstring(b, locale.days[date.getDay()]);\n break;\n\n // 'January'\n case 66 /* B */:\n luaL_addstring(b, locale.months[date.getMonth()]);\n break;\n\n // '19'\n case 67 /* C */:\n push_pad_2(b, Math.floor(date.getFullYear() / 100), 48 /* 0 */);\n break;\n\n // '01/01/70'\n case 68 /* D */:\n strftime(L, b, locale.formats.D, date);\n break;\n\n // '1970-01-01'\n case 70 /* F */:\n strftime(L, b, locale.formats.F, date);\n break;\n\n // '00'\n case 72 /* H */:\n push_pad_2(b, date.getHours(), 48 /* 0 */);\n break;\n\n // '12'\n case 73 /* I */:\n push_pad_2(b, (date.getHours() + 11) % 12 + 1, 48 /* 0 */);\n break;\n\n // '00'\n case 77 /* M */:\n push_pad_2(b, date.getMinutes(), 48 /* 0 */);\n break;\n\n // 'am'\n case 80 /* P */:\n luaL_addstring(b, date.getHours() < 12 ? locale.am : locale.pm);\n break;\n\n // '00:00'\n case 82 /* R */:\n strftime(L, b, locale.formats.R, date);\n break;\n\n // '00'\n case 83 /* S */:\n push_pad_2(b, date.getSeconds(), 48 /* 0 */);\n break;\n\n // '00:00:00'\n case 84 /* T */:\n strftime(L, b, locale.formats.T, date);\n break;\n\n // '00'\n case 85 /* U */:\n push_pad_2(b, week_number(date, \"sunday\"), 48 /* 0 */);\n break;\n\n // '00'\n case 87 /* W */:\n push_pad_2(b, week_number(date, \"monday\"), 48 /* 0 */);\n break;\n\n // '16:00:00'\n case 88 /* X */:\n strftime(L, b, locale.formats.X, date);\n break;\n\n // '1970'\n case 89 /* Y */:\n luaL_addstring(b, to_luastring(String(date.getFullYear())));\n break;\n\n // 'GMT'\n case 90 /* Z */: {\n let tzString = date.toString().match(/\\(([\\w\\s]+)\\)/);\n if (tzString)\n luaL_addstring(b, to_luastring(tzString[1]));\n break;\n }\n\n // 'Thu'\n case 97 /* a */:\n luaL_addstring(b, locale.shortDays[date.getDay()]);\n break;\n\n // 'Jan'\n case 98 /* b */:\n case 104 /* h */:\n luaL_addstring(b, locale.shortMonths[date.getMonth()]);\n break;\n\n // ''\n case 99 /* c */:\n strftime(L, b, locale.formats.c, date);\n break;\n\n // '01'\n case 100 /* d */:\n push_pad_2(b, date.getDate(), 48 /* 0 */);\n break;\n\n // ' 1'\n case 101 /* e */:\n push_pad_2(b, date.getDate(), 32 /* space */);\n break;\n\n // '000'\n case 106 /* j */: {\n let yday = Math.floor((date - new Date(date.getFullYear(), 0, 1)) / 86400000);\n if (yday < 100) {\n if (yday < 10)\n luaL_addchar(b, 48 /* 0 */);\n luaL_addchar(b, 48 /* 0 */);\n }\n luaL_addstring(b, to_luastring(String(yday)));\n break;\n }\n\n // ' 0'\n case 107 /* k */:\n push_pad_2(b, date.getHours(), 32 /* space */);\n break;\n\n // '12'\n case 108 /* l */:\n push_pad_2(b, (date.getHours() + 11) % 12 + 1, 32 /* space */);\n break;\n\n // '01'\n case 109 /* m */:\n push_pad_2(b, date.getMonth() + 1, 48 /* 0 */);\n break;\n\n // '\\n'\n case 110 /* n */:\n luaL_addchar(b, 10);\n break;\n\n // 'AM'\n case 112 /* p */:\n luaL_addstring(b, date.getHours() < 12 ? locale.AM : locale.PM);\n break;\n\n // '12:00:00 AM'\n case 114 /* r */:\n strftime(L, b, locale.formats.r, date);\n break;\n\n // '0'\n case 115 /* s */:\n luaL_addstring(b, to_luastring(String(Math.floor(date / 1000))));\n break;\n\n // '\\t'\n case 116 /* t */:\n luaL_addchar(b, 8);\n break;\n\n // '4'\n case 117 /* u */: {\n let day = date.getDay();\n luaL_addstring(b, to_luastring(String(day === 0 ? 7 : day)));\n break;\n }\n\n // '4'\n case 119 /* w */:\n luaL_addstring(b, to_luastring(String(date.getDay())));\n break;\n\n // '12/31/69'\n case 120 /* x */:\n strftime(L, b, locale.formats.x, date);\n break;\n\n // '70'\n case 121 /* y */:\n push_pad_2(b, date.getFullYear() % 100, 48 /* 0 */);\n break;\n\n // '+0000'\n case 122 /* z */: {\n let off = date.getTimezoneOffset();\n if (off > 0) {\n luaL_addchar(b, 45 /* - */);\n } else {\n off = -off;\n luaL_addchar(b, 43 /* + */);\n }\n push_pad_2(b, Math.floor(off/60), 48 /* 0 */);\n push_pad_2(b, off % 60, 48 /* 0 */);\n break;\n }\n }\n i += len;\n }\n }\n};\n\n\nconst checkoption = function(L, conv, i) {\n let option = LUA_STRFTIMEOPTIONS;\n let o = 0;\n let oplen = 1; /* length of options being checked */\n for (; o < option.length && oplen <= (conv.length - i); o += oplen) {\n if (option[o] === '|'.charCodeAt(0)) /* next block? */\n oplen++; /* will check options with next length (+1) */\n else if (luastring_eq(conv.subarray(i, i+oplen), option.subarray(o, o+oplen))) { /* match? */\n return oplen; /* return length */\n }\n }\n luaL_argerror(L, 1,\n lua_pushfstring(L, to_luastring(\"invalid conversion specifier '%%%s'\"), conv));\n};\n\n/* maximum size for an individual 'strftime' item */\n// const SIZETIMEFMT = 250;\n\n\nconst os_date = function(L) {\n let s = luaL_optlstring(L, 1, \"%c\");\n let stm = lua_isnoneornil(L, 2) ? new Date() : new Date(l_checktime(L, 2) * 1000);\n let utc = false;\n let i = 0;\n if (s[i] === '!'.charCodeAt(0)) { /* UTC? */\n utc = true;\n i++; /* skip '!' */\n }\n if (s[i] === \"*\".charCodeAt(0) && s[i+1] === \"t\".charCodeAt(0)) {\n lua_createtable(L, 0, 9); /* 9 = number of fields */\n setallfields(L, stm, utc);\n } else {\n let cc = new Uint8Array(4);\n cc[0] = \"%\".charCodeAt(0);\n let b = new luaL_Buffer();\n luaL_buffinit(L, b);\n strftime(L, b, s, stm);\n luaL_pushresult(b);\n }\n return 1;\n};\n\nconst os_time = function(L) {\n let t;\n if (lua_isnoneornil(L, 1)) /* called without args? */\n t = new Date(); /* get current time */\n else {\n luaL_checktype(L, 1, LUA_TTABLE);\n lua_settop(L, 1); /* make sure table is at the top */\n t = new Date(\n getfield(L, \"year\", -1, 0),\n getfield(L, \"month\", -1, 1),\n getfield(L, \"day\", -1, 0),\n getfield(L, \"hour\", 12, 0),\n getfield(L, \"min\", 0, 0),\n getfield(L, \"sec\", 0, 0)\n );\n setallfields(L, t);\n }\n\n lua_pushinteger(L, Math.floor(t / 1000));\n return 1;\n};\n\nconst l_checktime = function(L, arg) {\n let t = luaL_checkinteger(L, arg);\n // luaL_argcheck(L, t, arg, \"time out-of-bounds\");\n return t;\n};\n\nconst os_difftime = function(L) {\n let t1 = l_checktime(L, 1);\n let t2 = l_checktime(L, 2);\n lua_pushnumber(L, t1 - t2);\n return 1;\n};\n\nconst syslib = {\n \"date\": os_date,\n \"difftime\": os_difftime,\n \"time\": os_time\n};\n\nif (typeof process === \"undefined\") {\n syslib.clock = function(L) {\n lua_pushnumber(L, performance.now()/1000);\n return 1;\n };\n} else {\n /* Only with Node */\n const fs = require('fs');\n const tmp = require('tmp');\n const child_process = require('child_process');\n\n syslib.exit = function(L) {\n let status;\n if (lua_isboolean(L, 1))\n status = (lua_toboolean(L, 1) ? 0 : 1);\n else\n status = luaL_optinteger(L, 1, 0);\n if (lua_toboolean(L, 2))\n lua_close(L);\n if (L) process.exit(status); /* 'if' to avoid warnings for unreachable 'return' */\n return 0;\n };\n\n syslib.getenv = function(L) {\n let key = luaL_checkstring(L, 1);\n key = to_jsstring(key); /* https://github.com/nodejs/node/issues/16961 */\n if (Object.prototype.hasOwnProperty.call(process.env, key)) {\n lua_pushliteral(L, process.env[key]);\n } else {\n lua_pushnil(L);\n }\n return 1;\n };\n\n syslib.clock = function(L) {\n lua_pushnumber(L, process.uptime());\n return 1;\n };\n\n const lua_tmpname = function() {\n return tmp.tmpNameSync();\n };\n\n syslib.remove = function(L) {\n let filename = luaL_checkstring(L, 1);\n try {\n fs.unlinkSync(filename);\n } catch (e) {\n if (e.code === 'EISDIR') {\n try {\n fs.rmdirSync(filename);\n } catch (e) {\n return luaL_fileresult(L, false, filename, e);\n }\n } else {\n return luaL_fileresult(L, false, filename, e);\n }\n }\n return luaL_fileresult(L, true);\n };\n\n syslib.rename = function(L) {\n let fromname = luaL_checkstring(L, 1);\n let toname = luaL_checkstring(L, 2);\n try {\n fs.renameSync(fromname, toname);\n } catch (e) {\n return luaL_fileresult(L, false, false, e);\n }\n return luaL_fileresult(L, true);\n };\n\n syslib.tmpname = function(L) {\n let name = lua_tmpname();\n if (!name)\n return luaL_error(L, to_luastring(\"unable to generate a unique filename\"));\n lua_pushstring(L, to_luastring(name));\n return 1;\n };\n\n syslib.execute = function(L) {\n let cmd = luaL_optstring(L, 1, null);\n if (cmd !== null) {\n try {\n child_process.execSync(\n cmd,\n {\n stdio: [process.stdin, process.stdout, process.stderr]\n }\n );\n } catch (e) {\n return luaL_execresult(L, e);\n }\n\n return luaL_execresult(L, null);\n } else {\n /* Assume a shell is available.\n If it's good enough for musl it's good enough for us.\n http://git.musl-libc.org/cgit/musl/tree/src/process/system.c?id=ac45692a53a1b8d2ede329d91652d43c1fb5dc8d#n22\n */\n lua_pushboolean(L, 1);\n return 1;\n }\n };\n}\n\nconst luaopen_os = function(L) {\n luaL_newlib(L, syslib);\n return 1;\n};\n\nmodule.exports.luaopen_os = luaopen_os;\n","\"use strict\";\n\nconst { sprintf } = require('sprintf-js');\n\nconst {\n LUA_INTEGER_FMT,\n LUA_INTEGER_FRMLEN,\n LUA_MININTEGER,\n LUA_NUMBER_FMT,\n LUA_NUMBER_FRMLEN,\n frexp,\n lua_getlocaledecpoint\n} = require('./luaconf.js');\nconst {\n LUA_TBOOLEAN,\n LUA_TFUNCTION,\n LUA_TNIL,\n LUA_TNUMBER,\n LUA_TSTRING,\n LUA_TTABLE,\n lua_call,\n lua_createtable,\n lua_dump,\n lua_gettable,\n lua_gettop,\n lua_isinteger,\n lua_isstring,\n lua_pop,\n lua_pushcclosure,\n lua_pushinteger,\n lua_pushlightuserdata,\n lua_pushliteral,\n lua_pushlstring,\n lua_pushnil,\n lua_pushnumber,\n lua_pushstring,\n lua_pushvalue,\n lua_remove,\n lua_setfield,\n lua_setmetatable,\n lua_settop,\n lua_toboolean,\n lua_tointeger,\n lua_tonumber,\n lua_tostring,\n lua_touserdata,\n lua_type,\n lua_upvalueindex\n} = require('./lua.js');\nconst {\n luaL_Buffer,\n luaL_addchar,\n luaL_addlstring,\n luaL_addsize,\n luaL_addstring,\n luaL_addvalue,\n luaL_argcheck,\n luaL_argerror,\n luaL_buffinit,\n luaL_buffinitsize,\n luaL_checkinteger,\n luaL_checknumber,\n luaL_checkstack,\n luaL_checkstring,\n luaL_checktype,\n luaL_error,\n luaL_newlib,\n luaL_optinteger,\n luaL_optstring,\n luaL_prepbuffsize,\n luaL_pushresult,\n luaL_pushresultsize,\n luaL_tolstring,\n luaL_typename\n} = require('./lauxlib.js');\nconst lualib = require('./lualib.js');\nconst {\n luastring_eq,\n luastring_indexOf,\n to_jsstring,\n to_luastring\n} = require(\"./fengaricore.js\");\n\nconst sL_ESC = '%';\nconst L_ESC = sL_ESC.charCodeAt(0);\n\n/*\n** maximum number of captures that a pattern can do during\n** pattern-matching. This limit is arbitrary, but must fit in\n** an unsigned char.\n*/\nconst LUA_MAXCAPTURES = 32;\n\n// (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX))\nconst MAXSIZE = 2147483647;\n\n/* Give natural (i.e. strings end at the first \\0) length of a string represented by an array of bytes */\nconst strlen = function(s) {\n let len = luastring_indexOf(s, 0);\n return len > -1 ? len : s.length;\n};\n\n/* translate a relative string position: negative means back from end */\nconst posrelat = function(pos, len) {\n if (pos >= 0) return pos;\n else if (0 - pos > len) return 0;\n else return len + pos + 1;\n};\n\nconst str_sub = function(L) {\n let s = luaL_checkstring(L, 1);\n let l = s.length;\n let start = posrelat(luaL_checkinteger(L, 2), l);\n let end = posrelat(luaL_optinteger(L, 3, -1), l);\n if (start < 1) start = 1;\n if (end > l) end = l;\n if (start <= end)\n lua_pushstring(L, s.subarray(start - 1, (start - 1) + (end - start + 1)));\n else lua_pushliteral(L, \"\");\n return 1;\n};\n\nconst str_len = function(L) {\n lua_pushinteger(L, luaL_checkstring(L, 1).length);\n return 1;\n};\n\nconst str_char = function(L) {\n let n = lua_gettop(L); /* number of arguments */\n let b = new luaL_Buffer();\n let p = luaL_buffinitsize(L, b, n);\n for (let i = 1; i <= n; i++) {\n let c = luaL_checkinteger(L, i);\n luaL_argcheck(L, c >= 0 && c <= 255, \"value out of range\"); // Strings are 8-bit clean\n p[i-1] = c;\n }\n luaL_pushresultsize(b, n);\n return 1;\n};\n\nconst writer = function(L, b, size, B) {\n luaL_addlstring(B, b, size);\n return 0;\n};\n\nconst str_dump = function(L) {\n let b = new luaL_Buffer();\n let strip = lua_toboolean(L, 2);\n luaL_checktype(L, 1, LUA_TFUNCTION);\n lua_settop(L, 1);\n luaL_buffinit(L, b);\n if (lua_dump(L, writer, b, strip) !== 0)\n return luaL_error(L, to_luastring(\"unable to dump given function\"));\n luaL_pushresult(b);\n return 1;\n};\n\nconst SIZELENMOD = LUA_NUMBER_FRMLEN.length + 1;\n\nconst L_NBFD = 1;\n\nconst num2straux = function(x) {\n /* if 'inf' or 'NaN', format it like '%g' */\n if (Object.is(x, Infinity))\n return to_luastring('inf');\n else if (Object.is(x, -Infinity))\n return to_luastring('-inf');\n else if (Number.isNaN(x))\n return to_luastring('nan');\n else if (x === 0) { /* can be -0... */\n /* create \"0\" or \"-0\" followed by exponent */\n let zero = sprintf(LUA_NUMBER_FMT + \"x0p+0\", x);\n if (Object.is(x, -0))\n zero = \"-\" + zero;\n return to_luastring(zero);\n } else {\n let buff = \"\";\n let fe = frexp(x); /* 'x' fraction and exponent */\n let m = fe[0];\n let e = fe[1];\n if (m < 0) { /* is number negative? */\n buff += '-'; /* add signal */\n m = -m; /* make it positive */\n }\n buff += \"0x\"; /* add \"0x\" */\n buff += (m * (1<= 97) /* toupper */\n buff[i] = c & 0xdf;\n }\n } else if (fmt[SIZELENMOD] !== 97 /* 'a'.charCodeAt(0) */)\n luaL_error(L, to_luastring(\"modifiers for format '%%a'/'%%A' not implemented\"));\n return buff;\n};\n\n/*\n** Maximum size of each formatted item. This maximum size is produced\n** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.',\n** and '\\0') + number of decimal digits to represent maxfloat (which\n** is maximum exponent + 1). (99+3+1 then rounded to 120 for \"extra\n** expenses\", such as locale-dependent stuff)\n*/\n// const MAX_ITEM = 120;// TODO: + l_mathlim(MAX_10_EXP);\n\n\n/* valid flags in a format specification */\nconst FLAGS = to_luastring(\"-+ #0\");\n\n/*\n** maximum size of each format specification (such as \"%-099.99d\")\n*/\n// const MAX_FORMAT = 32;\n\nconst isalpha = e => (97 <= e && e <= 122) || (65 <= e && e <= 90);\nconst isdigit = e => 48 <= e && e <= 57;\nconst iscntrl = e => (0x00 <= e && e <= 0x1f) || e === 0x7f;\nconst isgraph = e => 33 <= e && e <= 126;\nconst islower = e => 97 <= e && e <= 122;\nconst isupper = e => 65 <= e && e <= 90;\nconst isalnum = e => (97 <= e && e <= 122) || (65 <= e && e <= 90) || (48 <= e && e <= 57);\nconst ispunct = e => isgraph(e) && !isalnum(e);\nconst isspace = e => e === 32 || (e >= 9 && e <= 13);\nconst isxdigit = e => (48 <= e && e <= 57) || (65 <= e && e <= 70) || (97 <= e && e <= 102);\n\nconst addquoted = function(b, s, len) {\n luaL_addchar(b, 34 /* '\"'.charCodeAt(0) */);\n let i = 0;\n while (len--) {\n if (s[i] === 34 /* '\"'.charCodeAt(0) */ ||\n s[i] === 92 /* '\\\\'.charCodeAt(0) */ ||\n s[i] === 10 /* '\\n'.charCodeAt(0) */) {\n luaL_addchar(b, 92 /* '\\\\'.charCodeAt(0) */);\n luaL_addchar(b, s[i]);\n } else if (iscntrl(s[i])) {\n let buff = ''+s[i];\n if (isdigit(s[i+1]))\n buff = '0'.repeat(3-buff.length) + buff; /* pad to 3 '0's */\n luaL_addstring(b, to_luastring(\"\\\\\" + buff));\n } else\n luaL_addchar(b, s[i]);\n i++;\n }\n luaL_addchar(b, 34 /* '\"'.charCodeAt(0) */);\n};\n\n/*\n** Ensures the 'buff' string uses a dot as the radix character.\n*/\nconst checkdp = function(buff) {\n if (luastring_indexOf(buff, 46 /* ('.').charCodeAt(0) */) < 0) { /* no dot? */\n let point = lua_getlocaledecpoint(); /* try locale point */\n let ppoint = luastring_indexOf(buff, point);\n if (ppoint) buff[ppoint] = 46 /* ('.').charCodeAt(0) */; /* change it to a dot */\n }\n};\n\nconst addliteral = function(L, b, arg) {\n switch(lua_type(L, arg)) {\n case LUA_TSTRING: {\n let s = lua_tostring(L, arg);\n addquoted(b, s, s.length);\n break;\n }\n case LUA_TNUMBER: {\n let buff;\n if (!lua_isinteger(L, arg)) { /* float? */\n let n = lua_tonumber(L, arg); /* write as hexa ('%a') */\n buff = lua_number2strx(L, to_luastring(`%${LUA_INTEGER_FRMLEN}a`), n);\n checkdp(buff); /* ensure it uses a dot */\n } else { /* integers */\n let n = lua_tointeger(L, arg);\n let format = (n === LUA_MININTEGER) /* corner case? */\n ? \"0x%\" + LUA_INTEGER_FRMLEN + \"x\" /* use hexa */\n : LUA_INTEGER_FMT; /* else use default format */\n buff = to_luastring(sprintf(format, n));\n }\n luaL_addstring(b, buff);\n break;\n }\n case LUA_TNIL: case LUA_TBOOLEAN: {\n luaL_tolstring(L, arg);\n luaL_addvalue(b);\n break;\n }\n default: {\n luaL_argerror(L, arg, to_luastring(\"value has no literal form\"));\n }\n }\n};\n\nconst scanformat = function(L, strfrmt, i, form) {\n let p = i;\n while (strfrmt[p] !== 0 && luastring_indexOf(FLAGS, strfrmt[p]) >= 0) p++; /* skip flags */\n if (p - i >= FLAGS.length)\n luaL_error(L, to_luastring(\"invalid format (repeated flags)\"));\n if (isdigit(strfrmt[p])) p++; /* skip width */\n if (isdigit(strfrmt[p])) p++; /* (2 digits at most) */\n if (strfrmt[p] === 46 /* '.'.charCodeAt(0) */) {\n p++;\n if (isdigit(strfrmt[p])) p++; /* skip precision */\n if (isdigit(strfrmt[p])) p++; /* (2 digits at most) */\n }\n if (isdigit(strfrmt[p]))\n luaL_error(L, to_luastring(\"invalid format (width or precision too long)\"));\n form[0] = 37 /* \"%\".charCodeAt(0) */;\n for (let j = 0; j < p - i + 1; j++)\n form[j+1] = strfrmt[i+j];\n return p;\n};\n\n/*\n** add length modifier into formats\n*/\nconst addlenmod = function(form, lenmod) {\n let l = form.length;\n let lm = lenmod.length;\n let spec = form[l - 1];\n for (let i = 0; i < lm; i++)\n form[i + l - 1] = lenmod[i];\n form[l + lm - 1] = spec;\n // form[l + lm] = 0;\n};\n\nconst str_format = function(L) {\n let top = lua_gettop(L);\n let arg = 1;\n let strfrmt = luaL_checkstring(L, arg);\n let i = 0;\n let b = new luaL_Buffer();\n luaL_buffinit(L, b);\n while (i < strfrmt.length) {\n if (strfrmt[i] !== L_ESC) {\n luaL_addchar(b, strfrmt[i++]);\n } else if (strfrmt[++i] === L_ESC) {\n luaL_addchar(b, strfrmt[i++]); /* %% */\n } else { /* format item */\n let form = []; /* to store the format ('%...') */\n if (++arg > top)\n luaL_argerror(L, arg, to_luastring(\"no value\"));\n i = scanformat(L, strfrmt, i, form);\n switch (String.fromCharCode(strfrmt[i++])) {\n case 'c': {\n // sprintf(String.fromCharCode(...form), luaL_checkinteger(L, arg));\n luaL_addchar(b, luaL_checkinteger(L, arg));\n break;\n }\n case 'd': case 'i':\n case 'o': case 'u': case 'x': case 'X': {\n let n = luaL_checkinteger(L, arg);\n addlenmod(form, to_luastring(LUA_INTEGER_FRMLEN, true));\n luaL_addstring(b, to_luastring(sprintf(String.fromCharCode(...form), n)));\n break;\n }\n case 'a': case 'A': {\n addlenmod(form, to_luastring(LUA_INTEGER_FRMLEN, true));\n luaL_addstring(b, lua_number2strx(L, form, luaL_checknumber(L, arg)));\n break;\n }\n case 'e': case 'E': case 'f':\n case 'g': case 'G': {\n let n = luaL_checknumber(L, arg);\n addlenmod(form, to_luastring(LUA_INTEGER_FRMLEN, true));\n luaL_addstring(b, to_luastring(sprintf(String.fromCharCode(...form), n)));\n break;\n }\n case 'q': {\n addliteral(L, b, arg);\n break;\n }\n case 's': {\n let s = luaL_tolstring(L, arg);\n if (form.length <= 2 || form[2] === 0) { /* no modifiers? */\n luaL_addvalue(b); /* keep entire string */\n } else {\n luaL_argcheck(L, s.length === strlen(s), arg, \"string contains zeros\");\n if (luastring_indexOf(form, 46 /* '.'.charCodeAt(0) */) < 0 && s.length >= 100) {\n /* no precision and string is too long to be formatted */\n luaL_addvalue(b); /* keep entire string */\n } else { /* format the string into 'buff' */\n // TODO: will fail if s is not valid UTF-8\n luaL_addstring(b, to_luastring(sprintf(String.fromCharCode(...form), to_jsstring(s))));\n lua_pop(L, 1); /* remove result from 'luaL_tolstring' */\n }\n }\n break;\n }\n default: { /* also treat cases 'pnLlh' */\n return luaL_error(L, to_luastring(\"invalid option '%%%c' to 'format'\"), strfrmt[i-1]);\n }\n }\n }\n }\n luaL_pushresult(b);\n return 1;\n};\n\n/* value used for padding */\nconst LUAL_PACKPADBYTE = 0x00;\n\n/* maximum size for the binary representation of an integer */\nconst MAXINTSIZE = 16;\n\nconst SZINT = 4; // Size of lua_Integer\n\n/* number of bits in a character */\nconst NB = 8;\n\n/* mask for one character (NB 1's) */\nconst MC = ((1 << NB) - 1);\n\nconst MAXALIGN = 8;\n\n/*\n** information to pack/unpack stuff\n*/\nclass Header {\n constructor(L) {\n this.L = L;\n this.islittle = true;\n this.maxalign = 1;\n }\n}\n\n/*\n** options for pack/unpack\n*/\nconst Kint = 0; /* signed integers */\nconst Kuint = 1; /* unsigned integers */\nconst Kfloat = 2; /* floating-point numbers */\nconst Kchar = 3; /* fixed-length strings */\nconst Kstring = 4; /* strings with prefixed length */\nconst Kzstr = 5; /* zero-terminated strings */\nconst Kpadding = 6; /* padding */\nconst Kpaddalign = 7; /* padding for alignment */\nconst Knop = 8; /* no-op (configuration or spaces) */\n\nconst digit = isdigit;\n\nconst getnum = function(fmt, df) {\n if (fmt.off >= fmt.s.length || !digit(fmt.s[fmt.off])) /* no number? */\n return df; /* return default value */\n else {\n let a = 0;\n do {\n a = a * 10 + (fmt.s[fmt.off++] - 48 /* '0'.charCodeAt(0) */);\n } while (fmt.off < fmt.s.length && digit(fmt.s[fmt.off]) && a <= (MAXSIZE - 9)/10);\n return a;\n }\n};\n\n/*\n** Read an integer numeral and raises an error if it is larger\n** than the maximum size for integers.\n*/\nconst getnumlimit = function(h, fmt, df) {\n let sz = getnum(fmt, df);\n if (sz > MAXINTSIZE || sz <= 0)\n luaL_error(h.L, to_luastring(\"integral size (%d) out of limits [1,%d]\"), sz, MAXINTSIZE);\n return sz;\n};\n\n/*\n** Read and classify next option. 'size' is filled with option's size.\n*/\nconst getoption = function(h, fmt) {\n let r = {\n opt: fmt.s[fmt.off++],\n size: 0 /* default */\n };\n switch (r.opt) {\n case 98 /*'b'*/: r.size = 1; r.opt = Kint; return r; // sizeof(char): 1\n case 66 /*'B'*/: r.size = 1; r.opt = Kuint; return r;\n case 104 /*'h'*/: r.size = 2; r.opt = Kint; return r; // sizeof(short): 2\n case 72 /*'H'*/: r.size = 2; r.opt = Kuint; return r;\n case 108 /*'l'*/: r.size = 4; r.opt = Kint; return r; // sizeof(long): 4\n case 76 /*'L'*/: r.size = 4; r.opt = Kuint; return r;\n case 106 /*'j'*/: r.size = 4; r.opt = Kint; return r; // sizeof(lua_Integer): 4\n case 74 /*'J'*/: r.size = 4; r.opt = Kuint; return r;\n case 84 /*'T'*/: r.size = 4; r.opt = Kuint; return r; // sizeof(size_t): 4\n case 102 /*'f'*/: r.size = 4; r.opt = Kfloat; return r; // sizeof(float): 4\n case 100 /*'d'*/: r.size = 8; r.opt = Kfloat; return r; // sizeof(double): 8\n case 110 /*'n'*/: r.size = 8; r.opt = Kfloat; return r; // sizeof(lua_Number): 8\n case 105 /*'i'*/: r.size = getnumlimit(h, fmt, 4); r.opt = Kint; return r; // sizeof(int): 4\n case 73 /*'I'*/: r.size = getnumlimit(h, fmt, 4); r.opt = Kuint; return r;\n case 115 /*'s'*/: r.size = getnumlimit(h, fmt, 4); r.opt = Kstring; return r;\n case 99 /*'c'*/: {\n r.size = getnum(fmt, -1);\n if (r.size === -1)\n luaL_error(h.L, to_luastring(\"missing size for format option 'c'\"));\n r.opt = Kchar;\n return r;\n }\n case 122 /*'z'*/: r.opt = Kzstr; return r;\n case 120 /*'x'*/: r.size = 1; r.opt = Kpadding; return r;\n case 88 /*'X'*/: r.opt = Kpaddalign; return r;\n case 32 /*' '*/: break;\n case 60 /*'<'*/: h.islittle = true; break;\n case 62 /*'>'*/: h.islittle = false; break;\n case 61 /*'='*/: h.islittle = true; break;\n case 33 /*'!'*/: h.maxalign = getnumlimit(h, fmt, MAXALIGN); break;\n default: luaL_error(h.L, to_luastring(\"invalid format option '%c'\"), r.opt);\n }\n r.opt = Knop;\n return r;\n};\n\n/*\n** Read, classify, and fill other details about the next option.\n** 'psize' is filled with option's size, 'notoalign' with its\n** alignment requirements.\n** Local variable 'size' gets the size to be aligned. (Kpadal option\n** always gets its full alignment, other options are limited by\n** the maximum alignment ('maxalign'). Kchar option needs no alignment\n** despite its size.\n*/\nconst getdetails = function(h, totalsize, fmt) {\n let r = {\n opt: NaN,\n size: NaN,\n ntoalign: NaN\n };\n\n let opt = getoption(h, fmt);\n r.size = opt.size;\n r.opt = opt.opt;\n let align = r.size; /* usually, alignment follows size */\n if (r.opt === Kpaddalign) { /* 'X' gets alignment from following option */\n if (fmt.off >= fmt.s.length || fmt.s[fmt.off] === 0)\n luaL_argerror(h.L, 1, to_luastring(\"invalid next option for option 'X'\"));\n else {\n let o = getoption(h, fmt);\n align = o.size;\n o = o.opt;\n if (o === Kchar || align === 0)\n luaL_argerror(h.L, 1, to_luastring(\"invalid next option for option 'X'\"));\n }\n }\n if (align <= 1 || r.opt === Kchar) /* need no alignment? */\n r.ntoalign = 0;\n else {\n if (align > h.maxalign) /* enforce maximum alignment */\n align = h.maxalign;\n if ((align & (align -1)) !== 0) /* is 'align' not a power of 2? */\n luaL_argerror(h.L, 1, to_luastring(\"format asks for alignment not power of 2\"));\n r.ntoalign = (align - (totalsize & (align - 1))) & (align - 1);\n }\n return r;\n};\n\n/*\n** Pack integer 'n' with 'size' bytes and 'islittle' endianness.\n** The final 'if' handles the case when 'size' is larger than\n** the size of a Lua integer, correcting the extra sign-extension\n** bytes if necessary (by default they would be zeros).\n*/\nconst packint = function(b, n, islittle, size, neg) {\n let buff = luaL_prepbuffsize(b, size);\n buff[islittle ? 0 : size - 1] = n & MC; /* first byte */\n for (let i = 1; i < size; i++) {\n n >>= NB;\n buff[islittle ? i : size - 1 - i] = n & MC;\n }\n if (neg && size > SZINT) { /* negative number need sign extension? */\n for (let i = SZINT; i < size; i++) /* correct extra bytes */\n buff[islittle ? i : size - 1 - i] = MC;\n }\n luaL_addsize(b, size); /* add result to buffer */\n};\n\nconst str_pack = function(L) {\n let b = new luaL_Buffer();\n let h = new Header(L);\n let fmt = {\n s: luaL_checkstring(L, 1), /* format string */\n off: 0\n };\n let arg = 1; /* current argument to pack */\n let totalsize = 0; /* accumulate total size of result */\n lua_pushnil(L); /* mark to separate arguments from string buffer */\n luaL_buffinit(L, b);\n while (fmt.off < fmt.s.length) {\n let details = getdetails(h, totalsize, fmt);\n let opt = details.opt;\n let size = details.size;\n let ntoalign = details.ntoalign;\n totalsize += ntoalign + size;\n while (ntoalign-- > 0)\n luaL_addchar(b, LUAL_PACKPADBYTE); /* fill alignment */\n arg++;\n switch (opt) {\n case Kint: { /* signed integers */\n let n = luaL_checkinteger(L, arg);\n if (size < SZINT) { /* need overflow check? */\n let lim = 1 << (size * 8) - 1;\n luaL_argcheck(L, -lim <= n && n < lim, arg, \"integer overflow\");\n }\n packint(b, n, h.islittle, size, n < 0);\n break;\n }\n case Kuint: { /* unsigned integers */\n let n = luaL_checkinteger(L, arg);\n if (size < SZINT)\n luaL_argcheck(L, (n>>>0) < (1 << (size * NB)), arg, \"unsigned overflow\");\n packint(b, n>>>0, h.islittle, size, false);\n break;\n }\n case Kfloat: { /* floating-point options */\n let buff = luaL_prepbuffsize(b, size);\n let n = luaL_checknumber(L, arg); /* get argument */\n let dv = new DataView(buff.buffer, buff.byteOffset, buff.byteLength);\n if (size === 4) dv.setFloat32(0, n, h.islittle);\n else dv.setFloat64(0, n, h.islittle);\n luaL_addsize(b, size);\n break;\n }\n case Kchar: { /* fixed-size string */\n let s = luaL_checkstring(L, arg);\n let len = s.length;\n luaL_argcheck(L, len <= size, arg, \"string longer than given size\");\n luaL_addlstring(b, s, len); /* add string */\n while (len++ < size) /* pad extra space */\n luaL_addchar(b, LUAL_PACKPADBYTE);\n break;\n }\n case Kstring: { /* strings with length count */\n let s = luaL_checkstring(L, arg);\n let len = s.length;\n luaL_argcheck(L,\n size >= 4 /* sizeof(size_t) */ || len < (1 << (size * NB)),\n arg, \"string length does not fit in given size\");\n packint(b, len, h.islittle, size, 0); /* pack length */\n luaL_addlstring(b, s, len);\n totalsize += len;\n break;\n }\n case Kzstr: { /* zero-terminated string */\n let s = luaL_checkstring(L, arg);\n let len = s.length;\n luaL_argcheck(L, luastring_indexOf(s, 0) < 0, arg, \"strings contains zeros\");\n luaL_addlstring(b, s, len);\n luaL_addchar(b, 0); /* add zero at the end */\n totalsize += len + 1;\n break;\n }\n case Kpadding: luaL_addchar(b, LUAL_PACKPADBYTE); /* fall through */\n case Kpaddalign: case Knop:\n arg--; /* undo increment */\n break;\n }\n }\n luaL_pushresult(b);\n return 1;\n};\n\nconst str_reverse = function(L) {\n let s = luaL_checkstring(L, 1);\n let l = s.length;\n let r = new Uint8Array(l);\n for (let i=0; i MAXSIZE / n) /* may overflow? */\n return luaL_error(L, to_luastring(\"resulting string too large\"));\n else {\n let totallen = n * l + (n - 1) * lsep;\n let b = new luaL_Buffer();\n let p = luaL_buffinitsize(L, b, totallen);\n let pi = 0;\n while (n-- > 1) { /* first n-1 copies (followed by separator) */\n p.set(s, pi);\n pi += l;\n if (lsep > 0) { /* empty 'memcpy' is not that cheap */\n p.set(sep, pi);\n pi += lsep;\n }\n }\n p.set(s, pi); /* last copy (not followed by separator) */\n luaL_pushresultsize(b, totallen);\n }\n return 1;\n};\n\nconst str_byte = function(L) {\n let s = luaL_checkstring(L, 1);\n let l = s.length;\n let posi = posrelat(luaL_optinteger(L, 2, 1), l);\n let pose = posrelat(luaL_optinteger(L, 3, posi), l);\n\n if (posi < 1) posi = 1;\n if (pose > l) pose = l;\n if (posi > pose) return 0; /* empty interval; return no values */\n if (pose - posi >= Number.MAX_SAFE_INTEGER) /* arithmetic overflow? */\n return luaL_error(L, \"string slice too long\");\n\n let n = (pose - posi) + 1;\n luaL_checkstack(L, n, \"string slice too long\");\n for (let i = 0; i < n; i++)\n lua_pushinteger(L, s[posi + i - 1]);\n return n;\n};\n\nconst str_packsize = function(L) {\n let h = new Header(L);\n let fmt = {\n s: luaL_checkstring(L, 1),\n off: 0\n };\n let totalsize = 0; /* accumulate total size of result */\n while (fmt.off < fmt.s.length) {\n let details = getdetails(h, totalsize, fmt);\n let opt = details.opt;\n let size = details.size;\n let ntoalign = details.ntoalign;\n size += ntoalign; /* total space used by option */\n luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, \"format result too large\");\n totalsize += size;\n switch (opt) {\n case Kstring: /* strings with length count */\n case Kzstr: /* zero-terminated string */\n luaL_argerror(L, 1, \"variable-length format\");\n /* call never return, but to avoid warnings: *//* fall through */\n default: break;\n }\n }\n lua_pushinteger(L, totalsize);\n return 1;\n};\n\n/*\n** Unpack an integer with 'size' bytes and 'islittle' endianness.\n** If size is smaller than the size of a Lua integer and integer\n** is signed, must do sign extension (propagating the sign to the\n** higher bits); if size is larger than the size of a Lua integer,\n** it must check the unread bytes to see whether they do not cause an\n** overflow.\n*/\nconst unpackint = function(L, str, islittle, size, issigned) {\n let res = 0;\n let limit = size <= SZINT ? size : SZINT;\n for (let i = limit - 1; i >= 0; i--) {\n res <<= NB;\n res |= str[islittle ? i : size - 1 - i];\n }\n if (size < SZINT) { /* real size smaller than lua_Integer? */\n if (issigned) { /* needs sign extension? */\n let mask = 1 << (size * NB - 1);\n res = ((res ^ mask) - mask); /* do sign extension */\n }\n } else if (size > SZINT) { /* must check unread bytes */\n let mask = !issigned || res >= 0 ? 0 : MC;\n for (let i = limit; i < size; i++) {\n if (str[islittle ? i : size - 1 - i] !== mask)\n luaL_error(L, to_luastring(\"%d-byte integer does not fit into Lua Integer\"), size);\n }\n }\n return res;\n};\n\nconst unpacknum = function(L, b, islittle, size) {\n lualib.lua_assert(b.length >= size);\n\n let dv = new DataView(new ArrayBuffer(size));\n for (let i = 0; i < size; i++)\n dv.setUint8(i, b[i], islittle);\n\n if (size == 4) return dv.getFloat32(0, islittle);\n else return dv.getFloat64(0, islittle);\n};\n\nconst str_unpack = function(L) {\n let h = new Header(L);\n let fmt = {\n s: luaL_checkstring(L, 1),\n off: 0\n };\n let data = luaL_checkstring(L, 2);\n let ld = data.length;\n let pos = posrelat(luaL_optinteger(L, 3, 1), ld) - 1;\n let n = 0; /* number of results */\n luaL_argcheck(L, pos <= ld && pos >= 0, 3, \"initial position out of string\");\n while (fmt.off < fmt.s.length) {\n let details = getdetails(h, pos, fmt);\n let opt = details.opt;\n let size = details.size;\n let ntoalign = details.ntoalign;\n if (/*ntoalign + size > ~pos ||*/ pos + ntoalign + size > ld)\n luaL_argerror(L, 2, to_luastring(\"data string too short\"));\n pos += ntoalign; /* skip alignment */\n /* stack space for item + next position */\n luaL_checkstack(L, 2, \"too many results\");\n n++;\n switch (opt) {\n case Kint:\n case Kuint: {\n let res = unpackint(L, data.subarray(pos), h.islittle, size, opt === Kint);\n lua_pushinteger(L, res);\n break;\n }\n case Kfloat: {\n let res = unpacknum(L, data.subarray(pos), h.islittle, size);\n lua_pushnumber(L, res);\n break;\n }\n case Kchar: {\n lua_pushstring(L, data.subarray(pos, pos + size));\n break;\n }\n case Kstring: {\n let len = unpackint(L, data.subarray(pos), h.islittle, size, 0);\n luaL_argcheck(L, pos + len + size <= ld, 2, \"data string too short\");\n lua_pushstring(L, data.subarray(pos + size, pos + size + len));\n pos += len; /* skip string */\n break;\n }\n case Kzstr: {\n let e = luastring_indexOf(data, 0, pos);\n if (e === -1) e = data.length - pos;\n lua_pushstring(L, data.subarray(pos, e));\n pos = e + 1; /* skip string plus final '\\0' */\n break;\n }\n case Kpaddalign: case Kpadding: case Knop:\n n--; /* undo increment */\n break;\n }\n pos += size;\n }\n lua_pushinteger(L, pos + 1); /* next position */\n return n + 1;\n};\n\nconst CAP_UNFINISHED = -1;\nconst CAP_POSITION = -2;\nconst MAXCCALLS = 200;\nconst SPECIALS = to_luastring(\"^$*+?.([%-\");\n\nclass MatchState {\n constructor(L) {\n this.src = null; /* unmodified source string */\n this.src_init = null; /* init of source string */\n this.src_end = null; /* end ('\\0') of source string */\n this.p = null; /* unmodified pattern string */\n this.p_end = null; /* end ('\\0') of pattern */\n this.L = L;\n this.matchdepth = NaN; /* control for recursive depth */\n this.level = NaN; /* total number of captures (finished or unfinished) */\n this.capture = [];\n }\n}\n\nconst check_capture = function(ms, l) {\n l = l - 49 /* '1'.charCodeAt(0) */;\n if (l < 0 || l >= ms.level || ms.capture[l].len === CAP_UNFINISHED)\n return luaL_error(ms.L, to_luastring(\"invalid capture index %%%d\"), l + 1);\n return l;\n};\n\nconst capture_to_close = function(ms) {\n let level = ms.level;\n for (level--; level >= 0; level--)\n if (ms.capture[level].len === CAP_UNFINISHED) return level;\n return luaL_error(ms.L, to_luastring(\"invalid pattern capture\"));\n};\n\nconst classend = function(ms, p) {\n switch(ms.p[p++]) {\n case L_ESC: {\n if (p === ms.p_end)\n luaL_error(ms.L, to_luastring(\"malformed pattern (ends with '%%')\"));\n return p + 1;\n }\n case 91 /* '['.charCodeAt(0) */: {\n if (ms.p[p] === 94 /* '^'.charCodeAt(0) */) p++;\n do { /* look for a ']' */\n if (p === ms.p_end)\n luaL_error(ms.L, to_luastring(\"malformed pattern (missing ']')\"));\n if (ms.p[p++] === L_ESC && p < ms.p_end)\n p++; /* skip escapes (e.g. '%]') */\n } while (ms.p[p] !== 93 /* ']'.charCodeAt(0) */);\n return p + 1;\n }\n default: {\n return p;\n }\n }\n};\n\nconst match_class = function(c, cl) {\n switch (cl) {\n case 97 /* 'a'.charCodeAt(0) */: return isalpha(c);\n case 65 /* 'A'.charCodeAt(0) */: return !isalpha(c);\n case 99 /* 'c'.charCodeAt(0) */: return iscntrl(c);\n case 67 /* 'C'.charCodeAt(0) */: return !iscntrl(c);\n case 100 /* 'd'.charCodeAt(0) */: return isdigit(c);\n case 68 /* 'D'.charCodeAt(0) */: return !isdigit(c);\n case 103 /* 'g'.charCodeAt(0) */: return isgraph(c);\n case 71 /* 'G'.charCodeAt(0) */: return !isgraph(c);\n case 108 /* 'l'.charCodeAt(0) */: return islower(c);\n case 76 /* 'L'.charCodeAt(0) */: return !islower(c);\n case 112 /* 'p'.charCodeAt(0) */: return ispunct(c);\n case 80 /* 'P'.charCodeAt(0) */: return !ispunct(c);\n case 115 /* 's'.charCodeAt(0) */: return isspace(c);\n case 83 /* 'S'.charCodeAt(0) */: return !isspace(c);\n case 117 /* 'u'.charCodeAt(0) */: return isupper(c);\n case 85 /* 'U'.charCodeAt(0) */: return !isupper(c);\n case 119 /* 'w'.charCodeAt(0) */: return isalnum(c);\n case 87 /* 'W'.charCodeAt(0) */: return !isalnum(c);\n case 120 /* 'x'.charCodeAt(0) */: return isxdigit(c);\n case 88 /* 'X'.charCodeAt(0) */: return !isxdigit(c);\n case 122 /* 'z'.charCodeAt(0) */: return (c === 0); /* deprecated option */\n case 90 /* 'z'.charCodeAt(0) */: return (c !== 0); /* deprecated option */\n default: return (cl === c);\n }\n};\n\nconst matchbracketclass = function(ms, c, p, ec) {\n let sig = true;\n if (ms.p[p + 1] === 94 /* '^'.charCodeAt(0) */) {\n sig = false;\n p++; /* skip the '^' */\n }\n while (++p < ec) {\n if (ms.p[p] === L_ESC) {\n p++;\n if (match_class(c, ms.p[p]))\n return sig;\n } else if (ms.p[p + 1] === 45 /* '-'.charCodeAt(0) */ && p + 2 < ec) {\n p += 2;\n if (ms.p[p - 2] <= c && c <= ms.p[p])\n return sig;\n } else if (ms.p[p] === c) return sig;\n }\n return !sig;\n};\n\nconst singlematch = function(ms, s, p, ep) {\n if (s >= ms.src_end)\n return false;\n else {\n let c = ms.src[s];\n switch (ms.p[p]) {\n case 46 /* '.'.charCodeAt(0) */: return true; /* matches any char */\n case L_ESC: return match_class(c, ms.p[p + 1]);\n case 91 /* '['.charCodeAt(0) */: return matchbracketclass(ms, c, p, ep - 1);\n default: return ms.p[p] === c;\n }\n }\n};\n\nconst matchbalance = function(ms, s, p) {\n if (p >= ms.p_end - 1)\n luaL_error(ms.L, to_luastring(\"malformed pattern (missing arguments to '%%b'\"));\n if (ms.src[s] !== ms.p[p])\n return null;\n else {\n let b = ms.p[p];\n let e = ms.p[p + 1];\n let cont = 1;\n while (++s < ms.src_end) {\n if (ms.src[s] === e) {\n if (--cont === 0) return s + 1;\n }\n else if (ms.src[s] === b) cont++;\n }\n }\n return null; /* string ends out of balance */\n};\n\nconst max_expand = function(ms, s, p, ep) {\n let i = 0; /* counts maximum expand for item */\n while (singlematch(ms, s + i, p, ep))\n i++;\n /* keeps trying to match with the maximum repetitions */\n while (i >= 0) {\n let res = match(ms, s + i, ep + 1);\n if (res) return res;\n i--; /* else didn't match; reduce 1 repetition to try again */\n }\n return null;\n};\n\nconst min_expand = function(ms, s, p, ep) {\n for (;;) {\n let res = match(ms, s, ep + 1);\n if (res !== null)\n return res;\n else if (singlematch(ms, s, p, ep))\n s++; /* try with one more repetition */\n else return null;\n }\n};\n\nconst start_capture = function(ms, s, p, what) {\n let level = ms.level;\n if (level >= LUA_MAXCAPTURES) luaL_error(ms.L, to_luastring(\"too many captures\"));\n ms.capture[level] = ms.capture[level] ? ms.capture[level] : {};\n ms.capture[level].init = s;\n ms.capture[level].len = what;\n ms.level = level + 1;\n let res;\n if ((res = match(ms, s, p)) === null) /* match failed? */\n ms.level--; /* undo capture */\n return res;\n};\n\nconst end_capture = function(ms, s, p) {\n let l = capture_to_close(ms);\n ms.capture[l].len = s - ms.capture[l].init; /* close capture */\n let res;\n if ((res = match(ms, s, p)) === null) /* match failed? */\n ms.capture[l].len = CAP_UNFINISHED; /* undo capture */\n return res;\n};\n\n/* Compare the elements of arrays 'a' and 'b' to see if they contain the same elements */\nconst array_cmp = function(a, ai, b, bi, len) {\n return luastring_eq(a.subarray(ai, ai+len), b.subarray(bi, bi+len));\n};\n\nconst match_capture = function(ms, s, l) {\n l = check_capture(ms, l);\n let len = ms.capture[l].len;\n if ((ms.src_end-s) >= len && array_cmp(ms.src, ms.capture[l].init, ms.src, s, len))\n return s+len;\n else return null;\n};\n\nconst match = function(ms, s, p) {\n let gotodefault = false;\n let gotoinit = true;\n\n if (ms.matchdepth-- === 0)\n luaL_error(ms.L, to_luastring(\"pattern too complex\"));\n\n while (gotoinit || gotodefault) {\n gotoinit = false;\n if (p !== ms.p_end) { /* end of pattern? */\n switch (gotodefault ? void 0 : ms.p[p]) {\n case 40 /* '('.charCodeAt(0) */: { /* start capture */\n if (ms.p[p + 1] === 41 /* ')'.charCodeAt(0) */) /* position capture? */\n s = start_capture(ms, s, p + 2, CAP_POSITION);\n else\n s = start_capture(ms, s, p + 1, CAP_UNFINISHED);\n break;\n }\n case 41 /* ')'.charCodeAt(0) */: { /* end capture */\n s = end_capture(ms, s, p + 1);\n break;\n }\n case 36 /* '$'.charCodeAt(0) */: {\n if (p + 1 !== ms.p_end) { /* is the '$' the last char in pattern? */\n gotodefault = true; /* no; go to default */\n break;\n }\n s = (ms.src.length - s) === 0 ? s : null; /* check end of string */\n break;\n }\n case L_ESC: { /* escaped sequences not in the format class[*+?-]? */\n switch (ms.p[p + 1]) {\n case 98 /* 'b'.charCodeAt(0) */: { /* balanced string? */\n s = matchbalance(ms, s, p + 2);\n if (s !== null) {\n p += 4;\n gotoinit = true;\n }\n break;\n }\n case 102 /* 'f'.charCodeAt(0) */: { /* frontier? */\n p += 2;\n if (ms.p[p] !== 91 /* '['.charCodeAt(0) */)\n luaL_error(ms.L, to_luastring(\"missing '[' after '%%f' in pattern\"));\n let ep = classend(ms, p); /* points to what is next */\n let previous = s === ms.src_init ? 0 : ms.src[s-1];\n if (!matchbracketclass(ms, previous, p, ep - 1) && matchbracketclass(ms, (s===ms.src_end)?0:ms.src[s], p, ep - 1)) {\n p = ep; gotoinit = true; break;\n }\n s = null; /* match failed */\n break;\n }\n case 48: case 49: case 50: case 51: case 52:\n case 53: case 54: case 55: case 56: case 57: { /* capture results (%0-%9)? */\n s = match_capture(ms, s, ms.p[p + 1]);\n if (s !== null) {\n p += 2; gotoinit = true;\n }\n break;\n }\n default: gotodefault = true;\n }\n break;\n }\n default: { /* pattern class plus optional suffix */\n gotodefault = false;\n let ep = classend(ms, p); /* points to optional suffix */\n /* does not match at least once? */\n if (!singlematch(ms, s, p, ep)) {\n if (ms.p[ep] === 42 /* '*'.charCodeAt(0) */ ||\n ms.p[ep] === 63 /* '?'.charCodeAt(0) */ ||\n ms.p[ep] === 45 /* '-'.charCodeAt(0) */\n ) { /* accept empty? */\n p = ep + 1; gotoinit = true; break;\n } else /* '+' or no suffix */\n s = null; /* fail */\n } else { /* matched once */\n switch (ms.p[ep]) { /* handle optional suffix */\n case 63 /* '?'.charCodeAt(0) */: { /* optional */\n let res;\n if ((res = match(ms, s + 1, ep + 1)) !== null)\n s = res;\n else {\n p = ep + 1; gotoinit = true;\n }\n break;\n }\n case 43 /* '+'.charCodeAt(0) */: /* 1 or more repetitions */\n s++; /* 1 match already done */\n /* fall through */\n case 42 /* '*'.charCodeAt(0) */: /* 0 or more repetitions */\n s = max_expand(ms, s, p, ep);\n break;\n case 45 /* '-'.charCodeAt(0) */: /* 0 or more repetitions (minimum) */\n s = min_expand(ms, s, p, ep);\n break;\n default: /* no suffix */\n s++; p = ep; gotoinit = true;\n }\n }\n break;\n }\n }\n }\n }\n ms.matchdepth++;\n return s;\n};\n\nconst push_onecapture = function(ms, i, s, e) {\n if (i >= ms.level) {\n if (i === 0)\n lua_pushlstring(ms.L, ms.src.subarray(s, e), e - s); /* add whole match */\n else\n luaL_error(ms.L, to_luastring(\"invalid capture index %%%d\"), i + 1);\n } else {\n let l = ms.capture[i].len;\n if (l === CAP_UNFINISHED) luaL_error(ms.L, to_luastring(\"unfinished capture\"));\n if (l === CAP_POSITION)\n lua_pushinteger(ms.L, ms.capture[i].init - ms.src_init + 1);\n else\n lua_pushlstring(ms.L, ms.src.subarray(ms.capture[i].init), l);\n }\n};\n\nconst push_captures = function(ms, s, e) {\n let nlevels = ms.level === 0 && ms.src.subarray(s) ? 1 : ms.level;\n luaL_checkstack(ms.L, nlevels, \"too many captures\");\n for (let i = 0; i < nlevels; i++)\n push_onecapture(ms, i, s, e);\n return nlevels; /* number of strings pushed */\n};\n\nconst nospecials = function(p, l) {\n for (let i=0; i>> 0,\n sl = subarr.length;\n\n if (sl === 0)\n return i;\n\n for (; (i = arr.indexOf(subarr[0], i)) !== -1; i++) {\n if (luastring_eq(arr.subarray(i, i+sl), subarr))\n return i;\n }\n\n return -1;\n};\n\nconst str_find_aux = function(L, find) {\n let s = luaL_checkstring(L, 1);\n let p = luaL_checkstring(L, 2);\n let ls = s.length;\n let lp = p.length;\n let init = posrelat(luaL_optinteger(L, 3, 1), ls);\n if (init < 1) init = 1;\n else if (init > ls + 1) { /* start after string's end? */\n lua_pushnil(L); /* cannot find anything */\n return 1;\n }\n /* explicit request or no special characters? */\n if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) {\n /* do a plain search */\n let f = find_subarray(s.subarray(init - 1), p, 0);\n if (f > -1) {\n lua_pushinteger(L, init + f);\n lua_pushinteger(L, init + f + lp - 1);\n return 2;\n }\n } else {\n let ms = new MatchState(L);\n let s1 = init - 1;\n let anchor = p[0] === 94 /* '^'.charCodeAt(0) */;\n if (anchor) {\n p = p.subarray(1); lp--; /* skip anchor character */\n }\n prepstate(ms, L, s, ls, p, lp);\n do {\n let res;\n reprepstate(ms);\n if ((res = match(ms, s1, 0)) !== null) {\n if (find) {\n lua_pushinteger(L, s1 + 1); /* start */\n lua_pushinteger(L, res); /* end */\n return push_captures(ms, null, 0) + 2;\n } else\n return push_captures(ms, s1, res);\n }\n } while (s1++ < ms.src_end && !anchor);\n }\n lua_pushnil(L); /* not found */\n return 1;\n};\n\nconst str_find = function(L) {\n return str_find_aux(L, 1);\n};\n\nconst str_match = function(L) {\n return str_find_aux(L, 0);\n};\n\n/* state for 'gmatch' */\nclass GMatchState {\n constructor() {\n this.src = NaN; /* current position */\n this.p = NaN; /* pattern */\n this.lastmatch = NaN; /* end of last match */\n this.ms = new MatchState(); /* match state */\n }\n}\n\nconst gmatch_aux = function(L) {\n let gm = lua_touserdata(L, lua_upvalueindex(3));\n gm.ms.L = L;\n for (let src = gm.src; src <= gm.ms.src_end; src++) {\n reprepstate(gm.ms);\n let e;\n if ((e = match(gm.ms, src, gm.p)) !== null && e !== gm.lastmatch) {\n gm.src = gm.lastmatch = e;\n return push_captures(gm.ms, src, e);\n }\n }\n return 0; /* not found */\n};\n\nconst str_gmatch = function(L) {\n let s = luaL_checkstring(L, 1);\n let p = luaL_checkstring(L, 2);\n let ls = s.length;\n let lp = p.length;\n lua_settop(L, 2); /* keep them on closure to avoid being collected */\n let gm = new GMatchState();\n lua_pushlightuserdata(L, gm);\n prepstate(gm.ms, L, s, ls, p, lp);\n gm.src = 0;\n gm.p = 0;\n gm.lastmatch = null;\n lua_pushcclosure(L, gmatch_aux, 3);\n return 1;\n};\n\nconst add_s = function(ms, b, s, e) {\n let L = ms.L;\n let news = lua_tostring(L, 3);\n let l = news.length;\n for (let i = 0; i < l; i++) {\n if (news[i] !== L_ESC)\n luaL_addchar(b, news[i]);\n else {\n i++; /* skip ESC */\n if (!isdigit(news[i])) {\n if (news[i] !== L_ESC)\n luaL_error(L, to_luastring(\"invalid use of '%c' in replacement string\"), L_ESC);\n luaL_addchar(b, news[i]);\n } else if (news[i] === 48 /* '0'.charCodeAt(0) */)\n luaL_addlstring(b, ms.src.subarray(s, e), e - s);\n else {\n push_onecapture(ms, news[i] - 49 /* '1'.charCodeAt(0) */, s, e);\n luaL_tolstring(L, -1);\n lua_remove(L, -2); /* remove original value */\n luaL_addvalue(b); /* add capture to accumulated result */\n }\n }\n }\n};\n\nconst add_value = function(ms, b, s, e, tr) {\n let L = ms.L;\n switch (tr) {\n case LUA_TFUNCTION: {\n lua_pushvalue(L, 3);\n let n = push_captures(ms, s, e);\n lua_call(L, n, 1);\n break;\n }\n case LUA_TTABLE: {\n push_onecapture(ms, 0, s, e);\n lua_gettable(L, 3);\n break;\n }\n default: { /* LUA_TNUMBER or LUA_TSTRING */\n add_s(ms, b, s, e);\n return;\n }\n }\n if (!lua_toboolean(L, -1)) { /* nil or false? */\n lua_pop(L, 1);\n lua_pushlstring(L, ms.src.subarray(s, e), e - s); /* keep original text */\n } else if (!lua_isstring(L, -1))\n luaL_error(L, to_luastring(\"invalid replacement value (a %s)\"), luaL_typename(L, -1));\n luaL_addvalue(b); /* add result to accumulator */\n};\n\nconst str_gsub = function(L) {\n let src = luaL_checkstring(L, 1); /* subject */\n let srcl = src.length;\n let p = luaL_checkstring(L, 2); /* pattern */\n let lp = p.length;\n let lastmatch = null; /* end of last match */\n let tr = lua_type(L, 3); /* replacement type */\n let max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */\n let anchor = p[0] === 94 /* '^'.charCodeAt(0) */;\n let n = 0; /* replacement count */\n let ms = new MatchState(L);\n let b = new luaL_Buffer();\n luaL_argcheck(L, tr === LUA_TNUMBER || tr === LUA_TSTRING || tr === LUA_TFUNCTION || tr === LUA_TTABLE, 3,\n \"string/function/table expected\");\n luaL_buffinit(L, b);\n if (anchor) {\n p = p.subarray(1); lp--; /* skip anchor character */\n }\n prepstate(ms, L, src, srcl, p, lp);\n src = 0; p = 0;\n while (n < max_s) {\n let e;\n reprepstate(ms);\n if ((e = match(ms, src, p)) !== null && e !== lastmatch) { /* match? */\n n++;\n add_value(ms, b, src, e, tr); /* add replacement to buffer */\n src = lastmatch = e;\n } else if (src < ms.src_end) /* otherwise, skip one character */\n luaL_addchar(b, ms.src[src++]);\n else break; /* end of subject */\n if (anchor) break;\n }\n luaL_addlstring(b, ms.src.subarray(src, ms.src_end), ms.src_end - src);\n luaL_pushresult(b);\n lua_pushinteger(L, n); /* number of substitutions */\n return 2;\n};\n\nconst strlib = {\n \"byte\": str_byte,\n \"char\": str_char,\n \"dump\": str_dump,\n \"find\": str_find,\n \"format\": str_format,\n \"gmatch\": str_gmatch,\n \"gsub\": str_gsub,\n \"len\": str_len,\n \"lower\": str_lower,\n \"match\": str_match,\n \"pack\": str_pack,\n \"packsize\": str_packsize,\n \"rep\": str_rep,\n \"reverse\": str_reverse,\n \"sub\": str_sub,\n \"unpack\": str_unpack,\n \"upper\": str_upper\n};\n\nconst createmetatable = function(L) {\n lua_createtable(L, 0, 1); /* table to be metatable for strings */\n lua_pushliteral(L, \"\"); /* dummy string */\n lua_pushvalue(L, -2); /* copy table */\n lua_setmetatable(L, -2); /* set table as metatable for strings */\n lua_pop(L, 1); /* pop dummy string */\n lua_pushvalue(L, -2); /* get string library */\n lua_setfield(L, -2, to_luastring(\"__index\", true)); /* metatable.__index = string */\n lua_pop(L, 1); /* pop metatable */\n};\n\nconst luaopen_string = function(L) {\n luaL_newlib(L, strlib);\n createmetatable(L);\n return 1;\n};\n\nmodule.exports.luaopen_string = luaopen_string;\n","\"use strict\";\n\nconst {\n lua_gettop,\n lua_pushcfunction,\n lua_pushfstring,\n lua_pushinteger,\n lua_pushnil,\n lua_pushstring,\n lua_pushvalue,\n lua_setfield,\n lua_tointeger\n} = require('./lua.js');\nconst {\n luaL_Buffer,\n luaL_addvalue,\n luaL_argcheck,\n luaL_buffinit,\n luaL_checkinteger,\n luaL_checkstack,\n luaL_checkstring,\n luaL_error,\n luaL_newlib,\n luaL_optinteger,\n luaL_pushresult\n} = require('./lauxlib.js');\nconst {\n luastring_of,\n to_luastring\n} = require(\"./fengaricore.js\");\n\nconst MAXUNICODE = 0x10FFFF;\n\nconst iscont = function(p) {\n let c = p & 0xC0;\n return c === 0x80;\n};\n\n/* translate a relative string position: negative means back from end */\nconst u_posrelat = function(pos, len) {\n if (pos >= 0) return pos;\n else if (0 - pos > len) return 0;\n else return len + pos + 1;\n};\n\n/*\n** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid.\n*/\nconst limits = [0xFF, 0x7F, 0x7FF, 0xFFFF];\nconst utf8_decode = function(s, pos) {\n let c = s[pos];\n let res = 0; /* final result */\n if (c < 0x80) /* ascii? */\n res = c;\n else {\n let count = 0; /* to count number of continuation bytes */\n while (c & 0x40) { /* still have continuation bytes? */\n let cc = s[pos + (++count)]; /* read next byte */\n if ((cc & 0xC0) !== 0x80) /* not a continuation byte? */\n return null; /* invalid byte sequence */\n res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */\n c <<= 1; /* to test next bit */\n }\n res |= ((c & 0x7F) << (count * 5)); /* add first byte */\n if (count > 3 || res > MAXUNICODE || res <= limits[count])\n return null; /* invalid byte sequence */\n pos += count; /* skip continuation bytes read */\n }\n\n return {\n code: res,\n pos: pos + 1\n };\n};\n\n/*\n** utf8len(s [, i [, j]]) --> number of characters that start in the\n** range [i,j], or nil + current position if 's' is not well formed in\n** that interval\n*/\nconst utflen = function(L) {\n let n = 0;\n let s = luaL_checkstring(L, 1);\n let len = s.length;\n let posi = u_posrelat(luaL_optinteger(L, 2, 1), len);\n let posj = u_posrelat(luaL_optinteger(L, 3, -1), len);\n\n luaL_argcheck(L, 1 <= posi && --posi <= len, 2, \"initial position out of string\");\n luaL_argcheck(L, --posj < len, 3, \"final position out of string\");\n\n while (posi <= posj) {\n let dec = utf8_decode(s, posi);\n if (dec === null) { /* conversion error? */\n lua_pushnil(L); /* return nil ... */\n lua_pushinteger(L, posi + 1); /* ... and current position */\n return 2;\n }\n posi = dec.pos;\n n++;\n }\n lua_pushinteger(L, n);\n return 1;\n};\n\nconst p_U = to_luastring(\"%U\");\nconst pushutfchar = function(L, arg) {\n let code = luaL_checkinteger(L, arg);\n luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, \"value out of range\");\n lua_pushfstring(L, p_U, code);\n};\n\n/*\n** utfchar(n1, n2, ...) -> char(n1)..char(n2)...\n*/\nconst utfchar = function(L) {\n let n = lua_gettop(L); /* number of arguments */\n if (n === 1) /* optimize common case of single char */\n pushutfchar(L, 1);\n else {\n let b = new luaL_Buffer();\n luaL_buffinit(L, b);\n for (let i = 1; i <= n; i++) {\n pushutfchar(L, i);\n luaL_addvalue(b);\n }\n luaL_pushresult(b);\n }\n return 1;\n};\n\n/*\n** offset(s, n, [i]) -> index where n-th character counting from\n** position 'i' starts; 0 means character at 'i'.\n*/\nconst byteoffset = function(L) {\n let s = luaL_checkstring(L, 1);\n let n = luaL_checkinteger(L, 2);\n let posi = n >= 0 ? 1 : s.length + 1;\n posi = u_posrelat(luaL_optinteger(L, 3, posi), s.length);\n\n luaL_argcheck(L, 1 <= posi && --posi <= s.length, 3, \"position out of range\");\n\n if (n === 0) {\n /* find beginning of current byte sequence */\n while (posi > 0 && iscont(s[posi])) posi--;\n } else {\n if (iscont(s[posi]))\n luaL_error(L, \"initial position is a continuation byte\");\n\n if (n < 0) {\n while (n < 0 && posi > 0) { /* move back */\n do { /* find beginning of previous character */\n posi--;\n } while (posi > 0 && iscont(s[posi]));\n n++;\n }\n } else {\n n--; /* do not move for 1st character */\n while (n > 0 && posi < s.length) {\n do { /* find beginning of next character */\n posi++;\n } while (iscont(s[posi])); /* (cannot pass final '\\0') */\n n--;\n }\n }\n }\n\n if (n === 0) /* did it find given character? */\n lua_pushinteger(L, posi + 1);\n else /* no such character */\n lua_pushnil(L);\n\n return 1;\n};\n\n/*\n** codepoint(s, [i, [j]]) -> returns codepoints for all characters\n** that start in the range [i,j]\n*/\nconst codepoint = function(L) {\n let s = luaL_checkstring(L, 1);\n let posi = u_posrelat(luaL_optinteger(L, 2, 1), s.length);\n let pose = u_posrelat(luaL_optinteger(L, 3, posi), s.length);\n\n luaL_argcheck(L, posi >= 1, 2, \"out of range\");\n luaL_argcheck(L, pose <= s.length, 3, \"out of range\");\n\n if (posi > pose) return 0; /* empty interval; return no values */\n if (pose - posi >= Number.MAX_SAFE_INTEGER)\n return luaL_error(L, \"string slice too long\");\n let n = (pose - posi) + 1;\n luaL_checkstack(L, n, \"string slice too long\");\n n = 0;\n for (posi -= 1; posi < pose;) {\n let dec = utf8_decode(s, posi);\n if (dec === null)\n return luaL_error(L, \"invalid UTF-8 code\");\n lua_pushinteger(L, dec.code);\n posi = dec.pos;\n n++;\n }\n return n;\n};\n\nconst iter_aux = function(L) {\n let s = luaL_checkstring(L, 1);\n let len = s.length;\n let n = lua_tointeger(L, 2) - 1;\n\n if (n < 0) /* first iteration? */\n n = 0; /* start from here */\n else if (n < len) {\n n++; /* skip current byte */\n while (iscont(s[n])) n++; /* and its continuations */\n }\n\n if (n >= len)\n return 0; /* no more codepoints */\n else {\n let dec = utf8_decode(s, n);\n if (dec === null || iscont(s[dec.pos]))\n return luaL_error(L, to_luastring(\"invalid UTF-8 code\"));\n lua_pushinteger(L, n + 1);\n lua_pushinteger(L, dec.code);\n return 2;\n }\n};\n\nconst iter_codes = function(L) {\n luaL_checkstring(L, 1);\n lua_pushcfunction(L, iter_aux);\n lua_pushvalue(L, 1);\n lua_pushinteger(L, 0);\n return 3;\n};\n\nconst funcs = {\n \"char\": utfchar,\n \"codepoint\": codepoint,\n \"codes\": iter_codes,\n \"len\": utflen,\n \"offset\": byteoffset\n};\n\n/* pattern to match a single UTF-8 character */\nconst UTF8PATT = luastring_of(91, 0, 45, 127, 194, 45, 244, 93, 91, 128, 45, 191, 93, 42);\n\nconst luaopen_utf8 = function(L) {\n luaL_newlib(L, funcs);\n lua_pushstring(L, UTF8PATT);\n lua_setfield(L, -2, to_luastring(\"charpattern\", true));\n return 1;\n};\n\nmodule.exports.luaopen_utf8 = luaopen_utf8;\n","\"use strict\";\n\nconst {\n LUA_OPLT,\n LUA_TNUMBER,\n lua_compare,\n lua_gettop,\n lua_isinteger,\n lua_isnoneornil,\n lua_pushboolean,\n lua_pushinteger,\n lua_pushliteral,\n lua_pushnil,\n lua_pushnumber,\n lua_pushvalue,\n lua_setfield,\n lua_settop,\n lua_tointeger,\n lua_tointegerx,\n lua_type\n} = require('./lua.js');\nconst {\n luaL_argcheck,\n luaL_argerror,\n luaL_checkany,\n luaL_checkinteger,\n luaL_checknumber,\n luaL_error,\n luaL_newlib,\n luaL_optnumber\n} = require('./lauxlib.js');\nconst {\n LUA_MAXINTEGER,\n LUA_MININTEGER,\n lua_numbertointeger\n} = require('./luaconf.js');\nconst { to_luastring } = require(\"./fengaricore.js\");\n\nlet rand_state;\n/* use same parameters as glibc LCG */\nconst l_rand = function() {\n rand_state = (1103515245 * rand_state + 12345) & 0x7fffffff;\n return rand_state;\n};\nconst l_srand = function(x) {\n rand_state = x|0;\n if (rand_state === 0)\n rand_state = 1;\n};\n\nconst math_random = function(L) {\n let low, up;\n /* use Math.random until randomseed is called */\n let r = (rand_state === void 0)?Math.random():(l_rand() / 0x80000000);\n switch (lua_gettop(L)) { /* check number of arguments */\n case 0:\n lua_pushnumber(L, r); /* Number between 0 and 1 */\n return 1;\n case 1: {\n low = 1;\n up = luaL_checkinteger(L, 1);\n break;\n }\n case 2: {\n low = luaL_checkinteger(L, 1);\n up = luaL_checkinteger(L, 2);\n break;\n }\n default: return luaL_error(L, \"wrong number of arguments\");\n }\n\n /* random integer in the interval [low, up] */\n luaL_argcheck(L, low <= up, 1, \"interval is empty\");\n luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1,\n \"interval too large\");\n\n r *= (up - low) + 1;\n lua_pushinteger(L, Math.floor(r) + low);\n return 1;\n};\n\nconst math_randomseed = function(L) {\n l_srand(luaL_checknumber(L, 1));\n l_rand(); /* discard first value to avoid undesirable correlations */\n return 0;\n};\n\nconst math_abs = function(L) {\n if (lua_isinteger(L, 1)) {\n let n = lua_tointeger(L, 1);\n if (n < 0) n = (-n)|0;\n lua_pushinteger(L, n);\n }\n else\n lua_pushnumber(L, Math.abs(luaL_checknumber(L, 1)));\n return 1;\n};\n\nconst math_sin = function(L) {\n lua_pushnumber(L, Math.sin(luaL_checknumber(L, 1)));\n return 1;\n};\n\nconst math_cos = function(L) {\n lua_pushnumber(L, Math.cos(luaL_checknumber(L, 1)));\n return 1;\n};\n\nconst math_tan = function(L) {\n lua_pushnumber(L, Math.tan(luaL_checknumber(L, 1)));\n return 1;\n};\n\nconst math_asin = function(L) {\n lua_pushnumber(L, Math.asin(luaL_checknumber(L, 1)));\n return 1;\n};\n\nconst math_acos = function(L) {\n lua_pushnumber(L, Math.acos(luaL_checknumber(L, 1)));\n return 1;\n};\n\nconst math_atan = function(L) {\n let y = luaL_checknumber(L, 1);\n let x = luaL_optnumber(L, 2, 1);\n lua_pushnumber(L, Math.atan2(y, x));\n return 1;\n};\n\nconst math_toint = function(L) {\n let n = lua_tointegerx(L, 1);\n if (n !== false)\n lua_pushinteger(L, n);\n else {\n luaL_checkany(L, 1);\n lua_pushnil(L); /* value is not convertible to integer */\n }\n return 1;\n};\n\nconst pushnumint = function(L, d) {\n let n = lua_numbertointeger(d);\n if (n !== false) /* does 'd' fit in an integer? */\n lua_pushinteger(L, n); /* result is integer */\n else\n lua_pushnumber(L, d); /* result is float */\n};\n\nconst math_floor = function(L) {\n if (lua_isinteger(L, 1))\n lua_settop(L, 1);\n else\n pushnumint(L, Math.floor(luaL_checknumber(L, 1)));\n\n return 1;\n};\n\nconst math_ceil = function(L) {\n if (lua_isinteger(L, 1))\n lua_settop(L, 1);\n else\n pushnumint(L, Math.ceil(luaL_checknumber(L, 1)));\n\n return 1;\n};\n\nconst math_sqrt = function(L) {\n lua_pushnumber(L, Math.sqrt(luaL_checknumber(L, 1)));\n return 1;\n};\n\nconst math_ult = function(L) {\n let a = luaL_checkinteger(L, 1);\n let b = luaL_checkinteger(L, 2);\n lua_pushboolean(L, (a >= 0)?(b<0 || a= 1, 1, \"value expected\");\n for (let i = 2; i <= n; i++){\n if (lua_compare(L, i, imin, LUA_OPLT))\n imin = i;\n }\n lua_pushvalue(L, imin);\n return 1;\n};\n\nconst math_max = function(L) {\n let n = lua_gettop(L); /* number of arguments */\n let imax = 1; /* index of current minimum value */\n luaL_argcheck(L, n >= 1, 1, \"value expected\");\n for (let i = 2; i <= n; i++){\n if (lua_compare(L, imax, i, LUA_OPLT))\n imax = i;\n }\n lua_pushvalue(L, imax);\n return 1;\n};\n\nconst math_type = function(L) {\n if (lua_type(L, 1) === LUA_TNUMBER) {\n if (lua_isinteger(L, 1))\n lua_pushliteral(L, \"integer\");\n else\n lua_pushliteral(L, \"float\");\n } else {\n luaL_checkany(L, 1);\n lua_pushnil(L);\n }\n return 1;\n};\n\nconst math_fmod = function(L) {\n if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) {\n let d = lua_tointeger(L, 2);\n /* no special case needed for -1 in javascript */\n if (d === 0) {\n luaL_argerror(L, 2, \"zero\");\n } else\n lua_pushinteger(L, (lua_tointeger(L, 1) % d)|0);\n } else {\n let a = luaL_checknumber(L, 1);\n let b = luaL_checknumber(L, 2);\n lua_pushnumber(L, a%b);\n }\n return 1;\n};\n\nconst math_modf = function(L) {\n if (lua_isinteger(L, 1)) {\n lua_settop(L, 1); /* number is its own integer part */\n lua_pushnumber(L, 0); /* no fractional part */\n } else {\n let n = luaL_checknumber(L, 1);\n let ip = n < 0 ? Math.ceil(n) : Math.floor(n);\n pushnumint(L, ip);\n lua_pushnumber(L, n === ip ? 0 : n - ip);\n }\n return 2;\n};\n\nconst mathlib = {\n \"abs\": math_abs,\n \"acos\": math_acos,\n \"asin\": math_asin,\n \"atan\": math_atan,\n \"ceil\": math_ceil,\n \"cos\": math_cos,\n \"deg\": math_deg,\n \"exp\": math_exp,\n \"floor\": math_floor,\n \"fmod\": math_fmod,\n \"log\": math_log,\n \"max\": math_max,\n \"min\": math_min,\n \"modf\": math_modf,\n \"rad\": math_rad,\n \"random\": math_random,\n \"randomseed\": math_randomseed,\n \"sin\": math_sin,\n \"sqrt\": math_sqrt,\n \"tan\": math_tan,\n \"tointeger\": math_toint,\n \"type\": math_type,\n \"ult\": math_ult\n};\n\nconst luaopen_math = function(L) {\n luaL_newlib(L, mathlib);\n lua_pushnumber(L, Math.PI);\n lua_setfield(L, -2, to_luastring(\"pi\", true));\n lua_pushnumber(L, Infinity);\n lua_setfield(L, -2, to_luastring(\"huge\", true));\n lua_pushinteger(L, LUA_MAXINTEGER);\n lua_setfield(L, -2, to_luastring(\"maxinteger\", true));\n lua_pushinteger(L, LUA_MININTEGER);\n lua_setfield(L, -2, to_luastring(\"mininteger\", true));\n return 1;\n};\n\nmodule.exports.luaopen_math = luaopen_math;\n","\"use strict\";\n\nconst {\n LUA_MASKCALL,\n LUA_MASKCOUNT,\n LUA_MASKLINE,\n LUA_MASKRET,\n LUA_REGISTRYINDEX,\n LUA_TFUNCTION,\n LUA_TNIL,\n LUA_TTABLE,\n LUA_TUSERDATA,\n lua_Debug,\n lua_call,\n lua_checkstack,\n lua_gethook,\n lua_gethookcount,\n lua_gethookmask,\n lua_getinfo,\n lua_getlocal,\n lua_getmetatable,\n lua_getstack,\n lua_getupvalue,\n lua_getuservalue,\n lua_insert,\n lua_iscfunction,\n lua_isfunction,\n lua_isnoneornil,\n lua_isthread,\n lua_newtable,\n lua_pcall,\n lua_pop,\n lua_pushboolean,\n lua_pushfstring,\n lua_pushinteger,\n lua_pushlightuserdata,\n lua_pushliteral,\n lua_pushnil,\n lua_pushstring,\n lua_pushvalue,\n lua_rawgetp,\n lua_rawsetp,\n lua_rotate,\n lua_setfield,\n lua_sethook,\n lua_setlocal,\n lua_setmetatable,\n lua_settop,\n lua_setupvalue,\n lua_setuservalue,\n lua_tojsstring,\n lua_toproxy,\n lua_tostring,\n lua_tothread,\n lua_touserdata,\n lua_type,\n lua_upvalueid,\n lua_upvaluejoin,\n lua_xmove\n} = require('./lua.js');\nconst {\n luaL_argcheck,\n luaL_argerror,\n luaL_checkany,\n luaL_checkinteger,\n luaL_checkstring,\n luaL_checktype,\n luaL_error,\n luaL_loadbuffer,\n luaL_newlib,\n luaL_optinteger,\n luaL_optstring,\n luaL_traceback,\n lua_writestringerror\n} = require('./lauxlib.js');\nconst lualib = require('./lualib.js');\nconst {\n luastring_indexOf,\n to_luastring\n} = require(\"./fengaricore.js\");\n\n/*\n** If L1 != L, L1 can be in any state, and therefore there are no\n** guarantees about its stack space; any push in L1 must be\n** checked.\n*/\nconst checkstack = function(L, L1, n) {\n if (L !== L1 && !lua_checkstack(L1, n))\n luaL_error(L, to_luastring(\"stack overflow\", true));\n};\n\nconst db_getregistry = function(L) {\n lua_pushvalue(L, LUA_REGISTRYINDEX);\n return 1;\n};\n\nconst db_getmetatable = function(L) {\n luaL_checkany(L, 1);\n if (!lua_getmetatable(L, 1)) {\n lua_pushnil(L); /* no metatable */\n }\n return 1;\n};\n\nconst db_setmetatable = function(L) {\n const t = lua_type(L, 2);\n luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, \"nil or table expected\");\n lua_settop(L, 2);\n lua_setmetatable(L, 1);\n return 1; /* return 1st argument */\n};\n\nconst db_getuservalue = function(L) {\n if (lua_type(L, 1) !== LUA_TUSERDATA)\n lua_pushnil(L);\n else\n lua_getuservalue(L, 1);\n return 1;\n};\n\n\nconst db_setuservalue = function(L) {\n luaL_checktype(L, 1, LUA_TUSERDATA);\n luaL_checkany(L, 2);\n lua_settop(L, 2);\n lua_setuservalue(L, 1);\n return 1;\n};\n\n/*\n** Auxiliary function used by several library functions: check for\n** an optional thread as function's first argument and set 'arg' with\n** 1 if this argument is present (so that functions can skip it to\n** access their other arguments)\n*/\nconst getthread = function(L) {\n if (lua_isthread(L, 1)) {\n return {\n arg: 1,\n thread: lua_tothread(L, 1)\n };\n } else {\n return {\n arg: 0,\n thread: L\n }; /* function will operate over current thread */\n }\n};\n\n/*\n** Variations of 'lua_settable', used by 'db_getinfo' to put results\n** from 'lua_getinfo' into result table. Key is always a string;\n** value can be a string, an int, or a boolean.\n*/\nconst settabss = function(L, k, v) {\n lua_pushstring(L, v);\n lua_setfield(L, -2, k);\n};\n\nconst settabsi = function(L, k, v) {\n lua_pushinteger(L, v);\n lua_setfield(L, -2, k);\n};\n\nconst settabsb = function(L, k, v) {\n lua_pushboolean(L, v);\n lua_setfield(L, -2, k);\n};\n\n\n/*\n** In function 'db_getinfo', the call to 'lua_getinfo' may push\n** results on the stack; later it creates the result table to put\n** these objects. Function 'treatstackoption' puts the result from\n** 'lua_getinfo' on top of the result table so that it can call\n** 'lua_setfield'.\n*/\nconst treatstackoption = function(L, L1, fname) {\n if (L == L1)\n lua_rotate(L, -2, 1); /* exchange object and table */\n else\n lua_xmove(L1, L, 1); /* move object to the \"main\" stack */\n lua_setfield(L, -2, fname); /* put object into table */\n};\n\n/*\n** Calls 'lua_getinfo' and collects all results in a new table.\n** L1 needs stack space for an optional input (function) plus\n** two optional outputs (function and line table) from function\n** 'lua_getinfo'.\n*/\nconst db_getinfo = function(L) {\n let ar = new lua_Debug();\n let thread = getthread(L);\n let arg = thread.arg;\n let L1 = thread.thread;\n let options = luaL_optstring(L, arg + 2, \"flnStu\");\n checkstack(L, L1, 3);\n if (lua_isfunction(L, arg + 1)) { /* info about a function? */\n options = lua_pushfstring(L, to_luastring(\">%s\"), options); /* add '>' to 'options' */\n lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */\n lua_xmove(L, L1, 1);\n } else { /* stack level */\n if (!lua_getstack(L1, luaL_checkinteger(L, arg + 1), ar)) {\n lua_pushnil(L); /* level out of range */\n return 1;\n }\n }\n\n if (!lua_getinfo(L1, options, ar))\n luaL_argerror(L, arg + 2, \"invalid option\");\n lua_newtable(L); /* table to collect results */\n if (luastring_indexOf(options, 83 /* 'S'.charCodeAt(0) */) > -1) {\n settabss(L, to_luastring(\"source\", true), ar.source);\n settabss(L, to_luastring(\"short_src\", true), ar.short_src);\n settabsi(L, to_luastring(\"linedefined\", true), ar.linedefined);\n settabsi(L, to_luastring(\"lastlinedefined\", true), ar.lastlinedefined);\n settabss(L, to_luastring(\"what\", true), ar.what);\n }\n if (luastring_indexOf(options, 108 /* 'l'.charCodeAt(0) */) > -1)\n settabsi(L, to_luastring(\"currentline\", true), ar.currentline);\n if (luastring_indexOf(options, 117 /* 'u'.charCodeAt(0) */) > -1) {\n settabsi(L, to_luastring(\"nups\", true), ar.nups);\n settabsi(L, to_luastring(\"nparams\", true), ar.nparams);\n settabsb(L, to_luastring(\"isvararg\", true), ar.isvararg);\n }\n if (luastring_indexOf(options, 110 /* 'n'.charCodeAt(0) */) > -1) {\n settabss(L, to_luastring(\"name\", true), ar.name);\n settabss(L, to_luastring(\"namewhat\", true), ar.namewhat);\n }\n if (luastring_indexOf(options, 116 /* 't'.charCodeAt(0) */) > -1)\n settabsb(L, to_luastring(\"istailcall\", true), ar.istailcall);\n if (luastring_indexOf(options, 76 /* 'L'.charCodeAt(0) */) > -1)\n treatstackoption(L, L1, to_luastring(\"activelines\", true));\n if (luastring_indexOf(options, 102 /* 'f'.charCodeAt(0) */) > -1)\n treatstackoption(L, L1, to_luastring(\"func\", true));\n return 1; /* return table */\n};\n\nconst db_getlocal = function(L) {\n let thread = getthread(L);\n let L1 = thread.thread;\n let arg = thread.arg;\n let ar = new lua_Debug();\n let nvar = luaL_checkinteger(L, arg + 2); /* local-variable index */\n if (lua_isfunction(L, arg + 1)) {\n lua_pushvalue(L, arg + 1); /* push function */\n lua_pushstring(L, lua_getlocal(L, null, nvar)); /* push local name */\n return 1; /* return only name (there is no value) */\n } else { /* stack-level argument */\n let level = luaL_checkinteger(L, arg + 1);\n if (!lua_getstack(L1, level, ar)) /* out of range? */\n return luaL_argerror(L, arg+1, \"level out of range\");\n checkstack(L, L1, 1);\n let name = lua_getlocal(L1, ar, nvar);\n if (name) {\n lua_xmove(L1, L, 1); /* move local value */\n lua_pushstring(L, name); /* push name */\n lua_rotate(L, -2, 1); /* re-order */\n return 2;\n }\n else {\n lua_pushnil(L); /* no name (nor value) */\n return 1;\n }\n }\n};\n\nconst db_setlocal = function(L) {\n let thread = getthread(L);\n let L1 = thread.thread;\n let arg = thread.arg;\n let ar = new lua_Debug();\n let level = luaL_checkinteger(L, arg + 1);\n let nvar = luaL_checkinteger(L, arg + 2);\n if (!lua_getstack(L1, level, ar)) /* out of range? */\n return luaL_argerror(L, arg + 1, \"level out of range\");\n luaL_checkany(L, arg + 3);\n lua_settop(L, arg + 3);\n checkstack(L, L1, 1);\n lua_xmove(L, L1, 1);\n let name = lua_setlocal(L1, ar, nvar);\n if (name === null)\n lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */\n lua_pushstring(L, name);\n return 1;\n};\n\n/*\n** get (if 'get' is true) or set an upvalue from a closure\n*/\nconst auxupvalue = function(L, get) {\n let n = luaL_checkinteger(L, 2); /* upvalue index */\n luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */\n let name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);\n if (name === null) return 0;\n lua_pushstring(L, name);\n lua_insert(L, -(get+1)); /* no-op if get is false */\n return get + 1;\n};\n\n\nconst db_getupvalue = function(L) {\n return auxupvalue(L, 1);\n};\n\nconst db_setupvalue = function(L) {\n luaL_checkany(L, 3);\n return auxupvalue(L, 0);\n};\n\n/*\n** Check whether a given upvalue from a given closure exists and\n** returns its index\n*/\nconst checkupval = function(L, argf, argnup) {\n let nup = luaL_checkinteger(L, argnup); /* upvalue index */\n luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */\n luaL_argcheck(L, (lua_getupvalue(L, argf, nup) !== null), argnup, \"invalid upvalue index\");\n return nup;\n};\n\nconst db_upvalueid = function(L) {\n let n = checkupval(L, 1, 2);\n lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));\n return 1;\n};\n\nconst db_upvaluejoin = function(L) {\n let n1 = checkupval(L, 1, 2);\n let n2 = checkupval(L, 3, 4);\n luaL_argcheck(L, !lua_iscfunction(L, 1), 1, \"Lua function expected\");\n luaL_argcheck(L, !lua_iscfunction(L, 3), 3, \"Lua function expected\");\n lua_upvaluejoin(L, 1, n1, 3, n2);\n return 0;\n};\n\n/*\n** The hook table at registry[HOOKKEY] maps threads to their current\n** hook function. (We only need the unique address of 'HOOKKEY'.)\n*/\nconst HOOKKEY = to_luastring(\"__hooks__\", true);\n\nconst hooknames = [\"call\", \"return\", \"line\", \"count\", \"tail call\"].map(e => to_luastring(e));\n\n/*\n** Call hook function registered at hook table for the current\n** thread (if there is one)\n*/\nconst hookf = function(L, ar) {\n lua_rawgetp(L, LUA_REGISTRYINDEX, HOOKKEY);\n let hooktable = lua_touserdata(L, -1);\n let proxy = hooktable.get(L);\n if (proxy) { /* is there a hook function? */\n proxy(L);\n lua_pushstring(L, hooknames[ar.event]); /* push event name */\n if (ar.currentline >= 0)\n lua_pushinteger(L, ar.currentline); /* push current line */\n else lua_pushnil(L);\n lualib.lua_assert(lua_getinfo(L, to_luastring(\"lS\"), ar));\n lua_call(L, 2, 0); /* call hook function */\n }\n};\n\n/*\n** Convert a string mask (for 'sethook') into a bit mask\n*/\nconst makemask = function(smask, count) {\n let mask = 0;\n if (luastring_indexOf(smask, 99 /* 'c'.charCodeAt(0) */) > -1) mask |= LUA_MASKCALL;\n if (luastring_indexOf(smask, 114 /* 'r'.charCodeAt(0) */) > -1) mask |= LUA_MASKRET;\n if (luastring_indexOf(smask, 108 /* 'l'.charCodeAt(0) */) > -1) mask |= LUA_MASKLINE;\n if (count > 0) mask |= LUA_MASKCOUNT;\n return mask;\n};\n\n/*\n** Convert a bit mask (for 'gethook') into a string mask\n*/\nconst unmakemask = function(mask, smask) {\n let i = 0;\n if (mask & LUA_MASKCALL) smask[i++] = 99 /* 'c'.charCodeAt(0) */;\n if (mask & LUA_MASKRET) smask[i++] = 114 /* 'r'.charCodeAt(0) */;\n if (mask & LUA_MASKLINE) smask[i++] = 108 /* 'l'.charCodeAt(0) */;\n return smask.subarray(0, i);\n};\n\nconst db_sethook = function(L) {\n let mask, count, func;\n let thread = getthread(L);\n let L1 = thread.thread;\n let arg = thread.arg;\n if (lua_isnoneornil(L, arg+1)) { /* no hook? */\n lua_settop(L, arg+1);\n func = null; mask = 0; count = 0; /* turn off hooks */\n }\n else {\n const smask = luaL_checkstring(L, arg + 2);\n luaL_checktype(L, arg+1, LUA_TFUNCTION);\n count = luaL_optinteger(L, arg + 3, 0);\n func = hookf; mask = makemask(smask, count);\n }\n /* as weak tables are not supported; use a JS weak-map */\n let hooktable;\n if (lua_rawgetp(L, LUA_REGISTRYINDEX, HOOKKEY) === LUA_TNIL) {\n hooktable = new WeakMap();\n lua_pushlightuserdata(L, hooktable);\n lua_rawsetp(L, LUA_REGISTRYINDEX, HOOKKEY); /* set it in position */\n } else {\n hooktable = lua_touserdata(L, -1);\n }\n let proxy = lua_toproxy(L, arg + 1); /* value (hook function) */\n hooktable.set(L1, proxy);\n lua_sethook(L1, func, mask, count);\n return 0;\n};\n\nconst db_gethook = function(L) {\n let thread = getthread(L);\n let L1 = thread.thread;\n let buff = new Uint8Array(5);\n let mask = lua_gethookmask(L1);\n let hook = lua_gethook(L1);\n if (hook === null) /* no hook? */\n lua_pushnil(L);\n else if (hook !== hookf) /* external hook? */\n lua_pushliteral(L, \"external hook\");\n else { /* hook table must exist */\n lua_rawgetp(L, LUA_REGISTRYINDEX, HOOKKEY);\n let hooktable = lua_touserdata(L, -1);\n let proxy = hooktable.get(L1);\n proxy(L);\n }\n lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */\n lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */\n return 3;\n};\n\nconst db_traceback = function(L) {\n let thread = getthread(L);\n let L1 = thread.thread;\n let arg = thread.arg;\n let msg = lua_tostring(L, arg + 1);\n if (msg === null && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */\n lua_pushvalue(L, arg + 1); /* return it untouched */\n else {\n let level = luaL_optinteger(L, arg + 2, L === L1 ? 1 : 0);\n luaL_traceback(L, L1, msg, level);\n }\n return 1;\n};\n\nconst dblib = {\n \"gethook\": db_gethook,\n \"getinfo\": db_getinfo,\n \"getlocal\": db_getlocal,\n \"getmetatable\": db_getmetatable,\n \"getregistry\": db_getregistry,\n \"getupvalue\": db_getupvalue,\n \"getuservalue\": db_getuservalue,\n \"sethook\": db_sethook,\n \"setlocal\": db_setlocal,\n \"setmetatable\": db_setmetatable,\n \"setupvalue\": db_setupvalue,\n \"setuservalue\": db_setuservalue,\n \"traceback\": db_traceback,\n \"upvalueid\": db_upvalueid,\n \"upvaluejoin\": db_upvaluejoin\n};\n\nlet getinput;\nif (typeof process !== \"undefined\") { // Only with Node\n const readlineSync = require('readline-sync');\n readlineSync.setDefaultOptions({\n prompt: 'lua_debug> '\n });\n getinput = function() {\n return readlineSync.prompt();\n };\n} else if (typeof window !== \"undefined\") {\n /* if in browser use window.prompt. Doesn't work from web workers.\n See https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt\n */\n getinput = function() {\n let input = prompt(\"lua_debug>\", \"\");\n return (input !== null) ? input : \"\";\n };\n}\nif (getinput) {\n dblib.debug = function(L) {\n for (;;) {\n let input = getinput();\n\n if (input === \"cont\")\n return 0;\n\n if (input.length === 0)\n continue;\n\n let buffer = to_luastring(input);\n if (luaL_loadbuffer(L, buffer, buffer.length, to_luastring(\"=(debug command)\", true))\n || lua_pcall(L, 0, 0, 0)) {\n lua_writestringerror(lua_tojsstring(L, -1), \"\\n\");\n }\n lua_settop(L, 0); /* remove eventual returns */\n }\n };\n}\n\nconst luaopen_debug = function(L) {\n luaL_newlib(L, dblib);\n return 1;\n};\n\nmodule.exports.luaopen_debug = luaopen_debug;\n","\"use strict\";\n\nconst {\n LUA_DIRSEP,\n LUA_EXEC_DIR,\n LUA_JSPATH_DEFAULT,\n LUA_PATH_DEFAULT,\n LUA_PATH_MARK,\n LUA_PATH_SEP\n} = require('./luaconf.js');\nconst {\n LUA_OK,\n LUA_REGISTRYINDEX,\n LUA_TNIL,\n LUA_TTABLE,\n lua_callk,\n lua_createtable,\n lua_getfield,\n lua_insert,\n lua_isfunction,\n lua_isnil,\n lua_isstring,\n lua_newtable,\n lua_pop,\n lua_pushboolean,\n lua_pushcclosure,\n lua_pushcfunction,\n lua_pushfstring,\n lua_pushglobaltable,\n lua_pushlightuserdata,\n lua_pushliteral,\n lua_pushlstring,\n lua_pushnil,\n lua_pushstring,\n lua_pushvalue,\n lua_rawgeti,\n lua_rawgetp,\n lua_rawseti,\n lua_rawsetp,\n lua_remove,\n lua_setfield,\n lua_setmetatable,\n lua_settop,\n lua_toboolean,\n lua_tostring,\n lua_touserdata,\n lua_upvalueindex\n} = require('./lua.js');\nconst {\n LUA_LOADED_TABLE,\n LUA_PRELOAD_TABLE,\n luaL_Buffer,\n luaL_addvalue,\n luaL_buffinit,\n luaL_checkstring,\n luaL_error,\n luaL_getsubtable,\n luaL_gsub,\n luaL_len,\n luaL_loadfile,\n luaL_newlib,\n luaL_optstring,\n luaL_pushresult,\n luaL_setfuncs\n} = require('./lauxlib.js');\nconst lualib = require('./lualib.js');\nconst {\n luastring_indexOf,\n to_jsstring,\n to_luastring,\n to_uristring\n} = require(\"./fengaricore.js\");\nconst fengari = require('./fengari.js');\n\nconst global_env = (function() {\n if (typeof process !== \"undefined\") {\n /* node */\n return global;\n } else if (typeof window !== \"undefined\") {\n /* browser window */\n return window;\n } else if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {\n /* web worker */\n return self;\n } else {\n /* unknown global env */\n return (0, eval)('this'); /* use non-strict mode to get global env */\n }\n})();\n\nconst JSLIBS = to_luastring(\"__JSLIBS__\");\nconst LUA_PATH_VAR = \"LUA_PATH\";\nconst LUA_JSPATH_VAR = \"LUA_JSPATH\";\n\nconst LUA_IGMARK = \"-\";\n\n/*\n** LUA_CSUBSEP is the character that replaces dots in submodule names\n** when searching for a JS loader.\n** LUA_LSUBSEP is the character that replaces dots in submodule names\n** when searching for a Lua loader.\n*/\nconst LUA_CSUBSEP = LUA_DIRSEP;\nconst LUA_LSUBSEP = LUA_DIRSEP;\n\n/* prefix for open functions in JS libraries */\nconst LUA_POF = to_luastring(\"luaopen_\");\n\n/* separator for open functions in JS libraries */\nconst LUA_OFSEP = to_luastring(\"_\");\nconst LIB_FAIL = \"open\";\n\nconst AUXMARK = to_luastring(\"\\x01\");\n\n\n/*\n** load JS library in file 'path'. If 'seeglb', load with all names in\n** the library global.\n** Returns the library; in case of error, returns NULL plus an\n** error string in the stack.\n*/\nlet lsys_load;\nif (typeof process === \"undefined\") {\n lsys_load = function(L, path, seeglb) {\n path = to_uristring(path);\n let xhr = new XMLHttpRequest();\n xhr.open(\"GET\", path, false);\n xhr.send();\n\n if (xhr.status < 200 || xhr.status >= 300) {\n lua_pushstring(L, to_luastring(`${xhr.status}: ${xhr.statusText}`));\n return null;\n }\n\n let code = xhr.response;\n /* Add sourceURL comment to get path in debugger+tracebacks */\n if (!/\\/\\/[#@] sourceURL=/.test(code))\n code += \" //# sourceURL=\" + path;\n let func;\n try {\n func = Function(\"fengari\", code);\n } catch (e) {\n lua_pushstring(L, to_luastring(`${e.name}: ${e.message}`));\n return null;\n }\n let res = func(fengari);\n if (typeof res === \"function\" || (typeof res === \"object\" && res !== null)) {\n return res;\n } else if (res === void 0) { /* assume library added symbols to global environment */\n return global_env;\n } else {\n lua_pushstring(L, to_luastring(`library returned unexpected type (${typeof res})`));\n return null;\n }\n };\n} else {\n const pathlib = require('path');\n lsys_load = function(L, path, seeglb) {\n path = to_jsstring(path);\n /* relative paths should be relative to cwd, not this js file */\n path = pathlib.resolve(process.cwd(), path);\n try {\n return require(path);\n } catch (e) {\n lua_pushstring(L, to_luastring(e.message));\n return null;\n }\n };\n}\n\n/*\n** Try to find a function named 'sym' in library 'lib'.\n** Returns the function; in case of error, returns NULL plus an\n** error string in the stack.\n*/\nconst lsys_sym = function(L, lib, sym) {\n let f = lib[to_jsstring(sym)];\n\n if (f && typeof f === 'function')\n return f;\n else {\n lua_pushfstring(L, to_luastring(\"undefined symbol: %s\"), sym);\n return null;\n }\n};\n\n/*\n** return registry.LUA_NOENV as a boolean\n*/\nconst noenv = function(L) {\n lua_getfield(L, LUA_REGISTRYINDEX, to_luastring(\"LUA_NOENV\"));\n let b = lua_toboolean(L, -1);\n lua_pop(L, 1); /* remove value */\n return b;\n};\n\nlet readable;\nif (typeof process !== \"undefined\") { // Only with Node\n const fs = require('fs');\n\n readable = function(filename) {\n try {\n let fd = fs.openSync(filename, 'r');\n fs.closeSync(fd);\n } catch (e) {\n return false;\n }\n return true;\n };\n} else {\n readable = function(path) {\n path = to_uristring(path);\n let xhr = new XMLHttpRequest();\n /* Following GET request done by searcher_Web will be cached */\n xhr.open(\"GET\", path, false);\n xhr.send();\n\n return xhr.status >= 200 && xhr.status <= 299;\n };\n}\n\n\n/* error codes for 'lookforfunc' */\nconst ERRLIB = 1;\nconst ERRFUNC = 2;\n\n/*\n** Look for a C function named 'sym' in a dynamically loaded library\n** 'path'.\n** First, check whether the library is already loaded; if not, try\n** to load it.\n** Then, if 'sym' is '*', return true (as library has been loaded).\n** Otherwise, look for symbol 'sym' in the library and push a\n** C function with that symbol.\n** Return 0 and 'true' or a function in the stack; in case of\n** errors, return an error code and an error message in the stack.\n*/\nconst lookforfunc = function(L, path, sym) {\n let reg = checkjslib(L, path); /* check loaded JS libraries */\n if (reg === null) { /* must load library? */\n reg = lsys_load(L, path, sym[0] === '*'.charCodeAt(0)); /* a global symbols if 'sym'=='*' */\n if (reg === null) return ERRLIB; /* unable to load library */\n addtojslib(L, path, reg);\n }\n if (sym[0] === '*'.charCodeAt(0)) { /* loading only library (no function)? */\n lua_pushboolean(L, 1); /* return 'true' */\n return 0; /* no errors */\n }\n else {\n let f = lsys_sym(L, reg, sym);\n if (f === null)\n return ERRFUNC; /* unable to find function */\n lua_pushcfunction(L, f); /* else create new function */\n return 0; /* no errors */\n }\n};\n\nconst ll_loadlib = function(L) {\n let path = luaL_checkstring(L, 1);\n let init = luaL_checkstring(L, 2);\n let stat = lookforfunc(L, path, init);\n if (stat === 0) /* no errors? */\n return 1; /* return the loaded function */\n else { /* error; error message is on stack top */\n lua_pushnil(L);\n lua_insert(L, -2);\n lua_pushliteral(L, (stat === ERRLIB) ? LIB_FAIL : \"init\");\n return 3; /* return nil, error message, and where */\n }\n};\n\nconst env = (function() {\n if (typeof process !== \"undefined\") {\n /* node */\n return process.env;\n } else {\n return global_env;\n }\n})();\n\n/*\n** Set a path\n*/\nconst setpath = function(L, fieldname, envname, dft) {\n let nver = `${envname}${lualib.LUA_VERSUFFIX}`;\n lua_pushstring(L, to_luastring(nver));\n let path = env[nver]; /* use versioned name */\n if (path === undefined) /* no environment variable? */\n path = env[envname]; /* try unversioned name */\n if (path === undefined || noenv(L)) /* no environment variable? */\n lua_pushstring(L, dft); /* use default */\n else {\n /* replace \";;\" by \";AUXMARK;\" and then AUXMARK by default path */\n path = luaL_gsub(\n L,\n to_luastring(path),\n to_luastring(LUA_PATH_SEP + LUA_PATH_SEP, true),\n to_luastring(LUA_PATH_SEP + to_jsstring(AUXMARK) + LUA_PATH_SEP, true)\n );\n luaL_gsub(L, path, AUXMARK, dft);\n lua_remove(L, -2); /* remove result from 1st 'gsub' */\n }\n lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */\n lua_pop(L, 1); /* pop versioned variable name */\n};\n\n/*\n** return registry.JSLIBS[path]\n*/\nconst checkjslib = function(L, path) {\n lua_rawgetp(L, LUA_REGISTRYINDEX, JSLIBS);\n lua_getfield(L, -1, path);\n let plib = lua_touserdata(L, -1); /* plib = JSLIBS[path] */\n lua_pop(L, 2); /* pop JSLIBS table and 'plib' */\n return plib;\n};\n\n/*\n** registry.JSLIBS[path] = plib -- for queries\n** registry.JSLIBS[#JSLIBS + 1] = plib -- also keep a list of all libraries\n*/\nconst addtojslib = function(L, path, plib) {\n lua_rawgetp(L, LUA_REGISTRYINDEX, JSLIBS);\n lua_pushlightuserdata(L, plib);\n lua_pushvalue(L, -1);\n lua_setfield(L, -3, path); /* JSLIBS[path] = plib */\n lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* JSLIBS[#JSLIBS + 1] = plib */\n lua_pop(L, 1); /* pop JSLIBS table */\n};\n\nconst pushnexttemplate = function(L, path) {\n while (path[0] === LUA_PATH_SEP.charCodeAt(0)) path = path.subarray(1); /* skip separators */\n if (path.length === 0) return null; /* no more templates */\n let l = luastring_indexOf(path, LUA_PATH_SEP.charCodeAt(0)); /* find next separator */\n if (l < 0) l = path.length;\n lua_pushlstring(L, path, l); /* template */\n return path.subarray(l);\n};\n\nconst searchpath = function(L, name, path, sep, dirsep) {\n let msg = new luaL_Buffer(); /* to build error message */\n luaL_buffinit(L, msg);\n if (sep[0] !== 0) /* non-empty separator? */\n name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */\n while ((path = pushnexttemplate(L, path)) !== null) {\n let filename = luaL_gsub(L, lua_tostring(L, -1), to_luastring(LUA_PATH_MARK, true), name);\n lua_remove(L, -2); /* remove path template */\n if (readable(filename)) /* does file exist and is readable? */\n return filename; /* return that file name */\n lua_pushfstring(L, to_luastring(\"\\n\\tno file '%s'\"), filename);\n lua_remove(L, -2); /* remove file name */\n luaL_addvalue(msg);\n }\n luaL_pushresult(msg); /* create error message */\n return null; /* not found */\n};\n\nconst ll_searchpath = function(L) {\n let f = searchpath(\n L,\n luaL_checkstring(L, 1),\n luaL_checkstring(L, 2),\n luaL_optstring(L, 3, \".\"),\n luaL_optstring(L, 4, LUA_DIRSEP)\n );\n if (f !== null) return 1;\n else { /* error message is on top of the stack */\n lua_pushnil(L);\n lua_insert(L, -2);\n return 2; /* return nil + error message */\n }\n};\n\nconst findfile = function(L, name, pname, dirsep) {\n lua_getfield(L, lua_upvalueindex(1), pname);\n let path = lua_tostring(L, -1);\n if (path === null)\n luaL_error(L, to_luastring(\"'package.%s' must be a string\"), pname);\n return searchpath(L, name, path, to_luastring(\".\"), dirsep);\n};\n\nconst checkload = function(L, stat, filename) {\n if (stat) { /* module loaded successfully? */\n lua_pushstring(L, filename); /* will be 2nd argument to module */\n return 2; /* return open function and file name */\n } else\n return luaL_error(L, to_luastring(\"error loading module '%s' from file '%s':\\n\\t%s\"),\n lua_tostring(L, 1), filename, lua_tostring(L, -1));\n};\n\nconst searcher_Lua = function(L) {\n let name = luaL_checkstring(L, 1);\n let filename = findfile(L, name, to_luastring(\"path\", true), to_luastring(LUA_LSUBSEP, true));\n if (filename === null) return 1; /* module not found in this path */\n return checkload(L, luaL_loadfile(L, filename) === LUA_OK, filename);\n};\n\n/*\n** Try to find a load function for module 'modname' at file 'filename'.\n** First, change '.' to '_' in 'modname'; then, if 'modname' has\n** the form X-Y (that is, it has an \"ignore mark\"), build a function\n** name \"luaopen_X\" and look for it. (For compatibility, if that\n** fails, it also tries \"luaopen_Y\".) If there is no ignore mark,\n** look for a function named \"luaopen_modname\".\n*/\nconst loadfunc = function(L, filename, modname) {\n let openfunc;\n modname = luaL_gsub(L, modname, to_luastring(\".\"), LUA_OFSEP);\n let mark = luastring_indexOf(modname, LUA_IGMARK.charCodeAt(0));\n if (mark >= 0) {\n openfunc = lua_pushlstring(L, modname, mark);\n openfunc = lua_pushfstring(L, to_luastring(\"%s%s\"), LUA_POF, openfunc);\n let stat = lookforfunc(L, filename, openfunc);\n if (stat !== ERRFUNC) return stat;\n modname = mark + 1; /* else go ahead and try old-style name */\n }\n openfunc = lua_pushfstring(L, to_luastring(\"%s%s\"), LUA_POF, modname);\n return lookforfunc(L, filename, openfunc);\n};\n\nconst searcher_C = function(L) {\n let name = luaL_checkstring(L, 1);\n let filename = findfile(L, name, to_luastring(\"jspath\", true), to_luastring(LUA_CSUBSEP, true));\n if (filename === null) return 1; /* module not found in this path */\n return checkload(L, (loadfunc(L, filename, name) === 0), filename);\n};\n\nconst searcher_Croot = function(L) {\n let name = luaL_checkstring(L, 1);\n let p = luastring_indexOf(name, '.'.charCodeAt(0));\n let stat;\n if (p < 0) return 0; /* is root */\n lua_pushlstring(L, name, p);\n let filename = findfile(L, lua_tostring(L, -1), to_luastring(\"jspath\", true), to_luastring(LUA_CSUBSEP, true));\n if (filename === null) return 1; /* root not found */\n if ((stat = loadfunc(L, filename, name)) !== 0) {\n if (stat != ERRFUNC)\n return checkload(L, 0, filename); /* real error */\n else { /* open function not found */\n lua_pushstring(L, to_luastring(\"\\n\\tno module '%s' in file '%s'\"), name, filename);\n return 1;\n }\n }\n lua_pushstring(L, filename); /* will be 2nd argument to module */\n return 2;\n};\n\nconst searcher_preload = function(L) {\n let name = luaL_checkstring(L, 1);\n lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);\n if (lua_getfield(L, -1, name) === LUA_TNIL) /* not found? */\n lua_pushfstring(L, to_luastring(\"\\n\\tno field package.preload['%s']\"), name);\n return 1;\n};\n\nconst findloader = function(L, name, ctx, k) {\n let msg = new luaL_Buffer(); /* to build error message */\n luaL_buffinit(L, msg);\n /* push 'package.searchers' to index 3 in the stack */\n if (lua_getfield(L, lua_upvalueindex(1), to_luastring(\"searchers\", true)) !== LUA_TTABLE)\n luaL_error(L, to_luastring(\"'package.searchers' must be a table\"));\n let ctx2 = {name: name, i: 1, msg: msg, ctx: ctx, k: k};\n return findloader_cont(L, LUA_OK, ctx2);\n};\n\nconst findloader_cont = function(L, status, ctx) {\n /* iterate over available searchers to find a loader */\n for (; ; ctx.i++) {\n if (status === LUA_OK) {\n if (lua_rawgeti(L, 3, ctx.i) === LUA_TNIL) { /* no more searchers? */\n lua_pop(L, 1); /* remove nil */\n luaL_pushresult(ctx.msg); /* create error message */\n luaL_error(L, to_luastring(\"module '%s' not found:%s\"), ctx.name, lua_tostring(L, -1));\n }\n lua_pushstring(L, ctx.name);\n lua_callk(L, 1, 2, ctx, findloader_cont); /* call it */\n } else {\n status = LUA_OK;\n }\n if (lua_isfunction(L, -2)) /* did it find a loader? */\n break; /* module loader found */\n else if (lua_isstring(L, -2)) { /* searcher returned error message? */\n lua_pop(L, 1); /* remove extra return */\n luaL_addvalue(ctx.msg); /* concatenate error message */\n }\n else\n lua_pop(L, 2); /* remove both returns */\n }\n return ctx.k(L, LUA_OK, ctx.ctx);\n};\n\nconst ll_require = function(L) {\n let name = luaL_checkstring(L, 1);\n lua_settop(L, 1); /* LOADED table will be at index 2 */\n lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);\n lua_getfield(L, 2, name); /* LOADED[name] */\n if (lua_toboolean(L, -1)) /* is it there? */\n return 1; /* package is already loaded */\n /* else must load package */\n lua_pop(L, 1); /* remove 'getfield' result */\n let ctx = name;\n return findloader(L, name, ctx, ll_require_cont);\n};\n\nconst ll_require_cont = function(L, status, ctx) {\n let name = ctx;\n lua_pushstring(L, name); /* pass name as argument to module loader */\n lua_insert(L, -2); /* name is 1st argument (before search data) */\n lua_callk(L, 2, 1, ctx, ll_require_cont2);\n return ll_require_cont2(L, LUA_OK, ctx); /* run loader to load module */\n};\n\nconst ll_require_cont2 = function(L, status, ctx) {\n let name = ctx;\n if (!lua_isnil(L, -1)) /* non-nil return? */\n lua_setfield(L, 2, name); /* LOADED[name] = returned value */\n if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */\n lua_pushboolean(L, 1); /* use true as result */\n lua_pushvalue(L, -1); /* extra copy to be returned */\n lua_setfield(L, 2, name); /* LOADED[name] = true */\n }\n return 1;\n};\n\nconst pk_funcs = {\n \"loadlib\": ll_loadlib,\n \"searchpath\": ll_searchpath\n};\n\nconst ll_funcs = {\n \"require\": ll_require\n};\n\nconst createsearcherstable = function(L) {\n let searchers = [searcher_preload, searcher_Lua, searcher_C, searcher_Croot, null];\n /* create 'searchers' table */\n lua_createtable(L);\n /* fill it with predefined searchers */\n for (let i = 0; searchers[i]; i++) {\n lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */\n lua_pushcclosure(L, searchers[i], 1);\n lua_rawseti(L, -2, i+1);\n }\n lua_setfield(L, -2, to_luastring(\"searchers\", true)); /* put it in field 'searchers' */\n};\n\n/*\n** create table JSLIBS to keep track of loaded JS libraries,\n** setting a finalizer to close all libraries when closing state.\n*/\nconst createjslibstable = function(L) {\n lua_newtable(L); /* create JSLIBS table */\n lua_createtable(L, 0, 1); /* create metatable for JSLIBS */\n lua_setmetatable(L, -2);\n lua_rawsetp(L, LUA_REGISTRYINDEX, JSLIBS); /* set JSLIBS table in registry */\n};\n\nconst luaopen_package = function(L) {\n createjslibstable(L);\n luaL_newlib(L, pk_funcs); /* create 'package' table */\n createsearcherstable(L);\n /* set paths */\n setpath(L, to_luastring(\"path\", true), LUA_PATH_VAR, LUA_PATH_DEFAULT);\n setpath(L, to_luastring(\"jspath\", true), LUA_JSPATH_VAR, LUA_JSPATH_DEFAULT);\n /* store config information */\n lua_pushliteral(L, LUA_DIRSEP + \"\\n\" + LUA_PATH_SEP + \"\\n\" + LUA_PATH_MARK + \"\\n\" +\n LUA_EXEC_DIR + \"\\n\" + LUA_IGMARK + \"\\n\");\n lua_setfield(L, -2, to_luastring(\"config\", true));\n /* set field 'loaded' */\n luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);\n lua_setfield(L, -2, to_luastring(\"loaded\", true));\n /* set field 'preload' */\n luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);\n lua_setfield(L, -2, to_luastring(\"preload\", true));\n lua_pushglobaltable(L);\n lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */\n luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */\n lua_pop(L, 1); /* pop global table */\n return 1; /* return 'package' table */\n};\n\nmodule.exports.luaopen_package = luaopen_package;\n","const {\n lua_pushinteger,\n lua_pushliteral,\n lua_setfield\n} = require('./lua.js');\nconst {\n luaL_newlib\n} = require('./lauxlib.js');\nconst {\n FENGARI_AUTHORS,\n FENGARI_COPYRIGHT,\n FENGARI_RELEASE,\n FENGARI_VERSION,\n FENGARI_VERSION_MAJOR,\n FENGARI_VERSION_MINOR,\n FENGARI_VERSION_NUM,\n FENGARI_VERSION_RELEASE,\n to_luastring\n} = require(\"./fengaricore.js\");\n\nconst luaopen_fengari = function(L) {\n luaL_newlib(L, {});\n lua_pushliteral(L, FENGARI_AUTHORS);\n lua_setfield(L, -2, to_luastring(\"AUTHORS\"));\n lua_pushliteral(L, FENGARI_COPYRIGHT);\n lua_setfield(L, -2, to_luastring(\"COPYRIGHT\"));\n lua_pushliteral(L, FENGARI_RELEASE);\n lua_setfield(L, -2, to_luastring(\"RELEASE\"));\n lua_pushliteral(L, FENGARI_VERSION);\n lua_setfield(L, -2, to_luastring(\"VERSION\"));\n lua_pushliteral(L, FENGARI_VERSION_MAJOR);\n lua_setfield(L, -2, to_luastring(\"VERSION_MAJOR\"));\n lua_pushliteral(L, FENGARI_VERSION_MINOR);\n lua_setfield(L, -2, to_luastring(\"VERSION_MINOR\"));\n lua_pushinteger(L, FENGARI_VERSION_NUM);\n lua_setfield(L, -2, to_luastring(\"VERSION_NUM\"));\n lua_pushliteral(L, FENGARI_VERSION_RELEASE);\n lua_setfield(L, -2, to_luastring(\"VERSION_RELEASE\"));\n return 1;\n};\n\nmodule.exports.luaopen_fengari = luaopen_fengari;\n","\"use strict\";\n\nimport {\n\tFENGARI_AUTHORS,\n\tFENGARI_COPYRIGHT,\n\tFENGARI_RELEASE,\n\tFENGARI_VERSION,\n\tFENGARI_VERSION_MAJOR,\n\tFENGARI_VERSION_MINOR,\n\tFENGARI_VERSION_NUM,\n\tFENGARI_VERSION_RELEASE,\n\n\tluastring_eq,\n\tluastring_indexOf,\n\tluastring_of,\n\tto_jsstring,\n\tto_luastring,\n\tto_uristring,\n\n\tlua,\n\tlauxlib,\n\tlualib\n} from 'fengari';\nimport * as interop from 'fengari-interop';\n\nconst {\n\tLUA_ERRRUN,\n\tLUA_ERRSYNTAX,\n\tLUA_OK,\n\tLUA_VERSION_MAJOR,\n\tLUA_VERSION_MINOR,\n\tlua_Debug,\n\tlua_getinfo,\n\tlua_getstack,\n\tlua_gettop,\n\tlua_insert,\n\tlua_pcall,\n\tlua_pop,\n\tlua_pushcfunction,\n\tlua_pushstring,\n\tlua_remove,\n\tlua_setglobal,\n\tlua_tojsstring\n} = lua;\nconst {\n\tluaL_loadbuffer,\n\tluaL_newstate,\n\tluaL_requiref\n} = lauxlib;\nconst {\n\tcheckjs,\n\tluaopen_js,\n\tpush,\n\ttojs\n} = interop;\n\nexport {\n\tFENGARI_AUTHORS,\n\tFENGARI_COPYRIGHT,\n\tFENGARI_RELEASE,\n\tFENGARI_VERSION,\n\tFENGARI_VERSION_MAJOR,\n\tFENGARI_VERSION_MINOR,\n\tFENGARI_VERSION_NUM,\n\tFENGARI_VERSION_RELEASE,\n\n\tluastring_eq,\n\tluastring_indexOf,\n\tluastring_of,\n\tto_jsstring,\n\tto_luastring,\n\tto_uristring,\n\n\tlua,\n\tlauxlib,\n\tlualib,\n\tinterop\n};\n\nexport const L = luaL_newstate();\n\n/* open standard libraries */\nlualib.luaL_openlibs(L);\nluaL_requiref(L, to_luastring(\"js\"), luaopen_js, 1);\nlua_pop(L, 1); /* remove lib */\n\nlua_pushstring(L, to_luastring(FENGARI_COPYRIGHT));\nlua_setglobal(L, to_luastring(\"_COPYRIGHT\"));\n\n/* Helper function to load a JS string of Lua source */\nexport function load(source, chunkname) {\n\tif (typeof source == \"string\")\n\t\tsource = to_luastring(source);\n\telse if (!(source instanceof Uint8Array))\n\t\tthrow new TypeError(\"expects an array of bytes or javascript string\");\n\n\tchunkname = chunkname?to_luastring(chunkname):null;\n\tlet ok = luaL_loadbuffer(L, source, null, chunkname);\n\tlet res;\n\tif (ok === LUA_ERRSYNTAX) {\n\t\tres = new SyntaxError(lua_tojsstring(L, -1));\n\t} else {\n\t\tres = tojs(L, -1);\n\t}\n\tlua_pop(L, 1);\n\tif (ok !== LUA_OK) {\n\t\tthrow res;\n\t}\n\treturn res;\n}\n\nif (typeof document !== 'undefined' && document instanceof HTMLDocument) {\n\t/* Have a document, e.g. we are in main browser window */\n\n\tconst crossorigin_to_credentials = function(crossorigin) {\n\t\tswitch(crossorigin) {\n\t\t\tcase \"anonymous\": return \"omit\";\n\t\t\tcase \"use-credentials\": return \"include\";\n\t\t\tdefault: return \"same-origin\";\n\t\t}\n\t};\n\n\tconst msghandler = function(L) {\n\t\tlet ar = new lua_Debug();\n\t\tif (lua_getstack(L, 2, ar))\n\t\t\tlua_getinfo(L, to_luastring(\"Sl\"), ar);\n\t\tpush(L, new ErrorEvent(\"error\", {\n\t\t\tbubbles: true,\n\t\t\tcancelable: true,\n\t\t\tmessage: lua_tojsstring(L, 1),\n\t\t\terror: tojs(L, 1),\n\t\t\tfilename: ar.short_src ? to_jsstring(ar.short_src) : void 0,\n\t\t\tlineno: ar.currentline > 0 ? ar.currentline : void 0\n\t\t}));\n\t\treturn 1;\n\t};\n\n\tconst run_lua_script = function(tag, code, chunkname) {\n\t\tlet ok = luaL_loadbuffer(L, code, null, chunkname);\n\t\tlet e;\n\t\tif (ok === LUA_ERRSYNTAX) {\n\t\t\tlet msg = lua_tojsstring(L, -1);\n\t\t\tlet filename = tag.src?tag.src:document.location;\n\t\t\tlet lineno = void 0; /* TODO: extract out of msg */\n\t\t\tlet syntaxerror = new SyntaxError(msg, filename, lineno);\n\t\t\te = new ErrorEvent(\"error\", {\n\t\t\t\tmessage: msg,\n\t\t\t\terror: syntaxerror,\n\t\t\t\tfilename: filename,\n\t\t\t\tlineno: lineno\n\t\t\t});\n\t\t} else if (ok === LUA_OK) {\n\t\t\t/* insert message handler below function */\n\t\t\tlet base = lua_gettop(L);\n\t\t\tlua_pushcfunction(L, msghandler);\n\t\t\tlua_insert(L, base);\n\t\t\t/* set document.currentScript.\n\t\t\t We can't set it normally; but we can create a getter for it, then remove the getter */\n\t\t\tObject.defineProperty(document, 'currentScript', {\n\t\t\t\tvalue: tag,\n\t\t\t\tconfigurable: true\n\t\t\t});\n\t\t\tok = lua_pcall(L, 0, 0, base);\n\t\t\t/* Remove the currentScript getter installed above; this restores normal behaviour */\n\t\t\tdelete document.currentScript;\n\t\t\t/* Remove message handler */\n\t\t\tlua_remove(L, base);\n\t\t\t/* Check if normal error that msghandler would have handled */\n\t\t\tif (ok === LUA_ERRRUN) {\n\t\t\t\te = checkjs(L, -1);\n\t\t\t}\n\t\t}\n\t\tif (ok !== LUA_OK) {\n\t\t\tif (e === void 0) {\n\t\t\t\te = new ErrorEvent(\"error\", {\n\t\t\t\t\tmessage: lua_tojsstring(L, -1),\n\t\t\t\t\terror: tojs(L, -1)\n\t\t\t\t});\n\t\t\t}\n\t\t\tlua_pop(L, 1);\n\t\t\tif (window.dispatchEvent(e)) {\n\t\t\t\tconsole.error(\"uncaught exception\", e.error);\n\t\t\t}\n\t\t}\n\t};\n\n\tconst process_xhr_response = function(xhr, tag, chunkname) {\n\t\tif (xhr.status >= 200 && xhr.status < 300) {\n\t\t\tlet code = xhr.response;\n\t\t\tif (typeof code === \"string\") {\n\t\t\t\tcode = to_luastring(xhr.response);\n\t\t\t} else { /* is an array buffer */\n\t\t\t\tcode = new Uint8Array(code);\n\t\t\t}\n\t\t\t/* TODO: subresource integrity check? */\n\t\t\trun_lua_script(tag, code, chunkname);\n\t\t} else {\n\t\t\ttag.dispatchEvent(new Event(\"error\"));\n\t\t}\n\t};\n\n\tconst run_lua_script_tag = function(tag) {\n\t\tif (tag.src) {\n\t\t\tlet chunkname = to_luastring(\"@\"+tag.src);\n\t\t\t/* JS script tags are async after document has loaded */\n\t\t\tif (document.readyState === \"complete\" || tag.async) {\n\t\t\t\tif (typeof fetch === \"function\") {\n\t\t\t\t\tfetch(tag.src, {\n\t\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\t\tcredentials: crossorigin_to_credentials(tag.crossorigin),\n\t\t\t\t\t\tredirect: \"follow\",\n\t\t\t\t\t\tintegrity: tag.integrity\n\t\t\t\t\t}).then(function(resp) {\n\t\t\t\t\t\tif (resp.ok) {\n\t\t\t\t\t\t\treturn resp.arrayBuffer();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthrow new Error(\"unable to fetch\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}).then(function(buffer) {\n\t\t\t\t\t\tlet code = new Uint8Array(buffer);\n\t\t\t\t\t\trun_lua_script(tag, code, chunkname);\n\t\t\t\t\t}).catch(function(reason) {\n\t\t\t\t\t\ttag.dispatchEvent(new Event(\"error\"));\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tlet xhr = new XMLHttpRequest();\n\t\t\t\t\txhr.open(\"GET\", tag.src, true);\n\t\t\t\t\txhr.responseType = \"arraybuffer\";\n\t\t\t\t\txhr.onreadystatechange = function() {\n\t\t\t\t\t\tif (xhr.readyState === 4)\n\t\t\t\t\t\t\tprocess_xhr_response(xhr, tag, chunkname);\n\t\t\t\t\t};\n\t\t\t\t\txhr.send();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t/* Needs to be synchronous: use an XHR */\n\t\t\t\tlet xhr = new XMLHttpRequest();\n\t\t\t\txhr.open(\"GET\", tag.src, false);\n\t\t\t\txhr.send();\n\t\t\t\tprocess_xhr_response(xhr, tag, chunkname);\n\t\t\t}\n\t\t} else {\n\t\t\tlet code = to_luastring(tag.innerHTML);\n\t\t\tlet chunkname = tag.id ? to_luastring(\"=\"+tag.id) : code;\n\t\t\trun_lua_script(tag, code, chunkname);\n\t\t}\n\t};\n\n\tconst contentTypeRegexp = /^(.*?\\/.*?)([\\t ]*;.*)?$/;\n\tconst luaVersionRegex = /^(\\d+)\\.(\\d+)$/;\n\tconst try_tag = function(tag) {\n\t\tif (tag.tagName !== \"SCRIPT\")\n\t\t\treturn;\n\n\t\t/* strip off mime type parameters */\n\t\tlet contentTypeMatch = contentTypeRegexp.exec(tag.type);\n\t\tif (!contentTypeMatch)\n\t\t\treturn;\n\t\tlet mimetype = contentTypeMatch[1];\n\t\tif (mimetype !== \"application/lua\" && mimetype !== \"text/lua\")\n\t\t\treturn;\n\n\t\tif (tag.hasAttribute(\"lua-version\")) {\n\t\t\tlet lua_version = luaVersionRegex.exec(tag.getAttribute(\"lua-version\"));\n\t\t\tif (!lua_version || lua_version[1] !== LUA_VERSION_MAJOR || lua_version[2] !== LUA_VERSION_MINOR)\n\t\t\t\treturn;\n\t\t}\n\n\t\trun_lua_script_tag(tag);\n\t};\n\n\tif (typeof MutationObserver !== 'undefined') {\n\t\t/* watch for new script tags added to document */\n\t\t(new MutationObserver(function(records, observer) {\n\t\t\tfor (let i=0; i fs.lasttarget) { /* no jumps to current position? */\n previous = fs.f.code[fs.pc-1];\n if (previous.opcode === OpCodesI.OP_LOADNIL) { /* previous is LOADNIL? */\n let pfrom = previous.A; /* get previous range */\n let pl = pfrom + previous.B;\n if ((pfrom <= from && from <= pl + 1) ||\n (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */\n if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */\n if (pl > l) l = pl; /* l = max(l, pl) */\n lopcodes.SETARG_A(previous, from);\n lopcodes.SETARG_B(previous, l - from);\n return;\n }\n } /* else go through */\n }\n luaK_codeABC(fs, OpCodesI.OP_LOADNIL, from, n - 1, 0); /* else no optimization */\n};\n\nconst getinstruction = function(fs, e) {\n return fs.f.code[e.u.info];\n};\n\n/*\n** Gets the destination address of a jump instruction. Used to traverse\n** a list of jumps.\n*/\nconst getjump = function(fs, pc) {\n let offset = fs.f.code[pc].sBx;\n if (offset === NO_JUMP) /* point to itself represents end of list */\n return NO_JUMP; /* end of list */\n else\n return pc + 1 + offset; /* turn offset into absolute position */\n};\n\n/*\n** Fix jump instruction at position 'pc' to jump to 'dest'.\n** (Jump addresses are relative in Lua)\n*/\nconst fixjump = function(fs, pc, dest) {\n let jmp = fs.f.code[pc];\n let offset = dest - (pc + 1);\n lua_assert(dest !== NO_JUMP);\n if (Math.abs(offset) > lopcodes.MAXARG_sBx)\n llex.luaX_syntaxerror(fs.ls, to_luastring(\"control structure too long\", true));\n lopcodes.SETARG_sBx(jmp, offset);\n};\n\n/*\n** Concatenate jump-list 'l2' into jump-list 'l1'\n*/\nconst luaK_concat = function(fs, l1, l2) {\n if (l2 === NO_JUMP) return l1; /* nothing to concatenate? */\n else if (l1 === NO_JUMP) /* no original list? */\n l1 = l2;\n else {\n let list = l1;\n let next = getjump(fs, list);\n while (next !== NO_JUMP) { /* find last element */\n list = next;\n next = getjump(fs, list);\n }\n fixjump(fs, list, l2);\n }\n\n return l1;\n};\n\n/*\n** Create a jump instruction and return its position, so its destination\n** can be fixed later (with 'fixjump'). If there are jumps to\n** this position (kept in 'jpc'), link them all together so that\n** 'patchlistaux' will fix all them directly to the final destination.\n*/\nconst luaK_jump = function (fs) {\n let jpc = fs.jpc; /* save list of jumps to here */\n fs.jpc = NO_JUMP; /* no more jumps to here */\n let j = luaK_codeAsBx(fs, OpCodesI.OP_JMP, 0, NO_JUMP);\n j = luaK_concat(fs, j, jpc); /* keep them on hold */\n return j;\n};\n\nconst luaK_jumpto = function(fs, t) {\n return luaK_patchlist(fs, luaK_jump(fs), t);\n};\n\n/*\n** Code a 'return' instruction\n*/\nconst luaK_ret = function(fs, first, nret) {\n luaK_codeABC(fs, OpCodesI.OP_RETURN, first, nret + 1, 0);\n};\n\n/*\n** Code a \"conditional jump\", that is, a test or comparison opcode\n** followed by a jump. Return jump position.\n*/\nconst condjump = function(fs, op, A, B, C) {\n luaK_codeABC(fs, op, A, B, C);\n return luaK_jump(fs);\n};\n\n/*\n** returns current 'pc' and marks it as a jump target (to avoid wrong\n** optimizations with consecutive instructions not in the same basic block).\n*/\nconst luaK_getlabel = function(fs) {\n fs.lasttarget = fs.pc;\n return fs.pc;\n};\n\n/*\n** Returns the position of the instruction \"controlling\" a given\n** jump (that is, its condition), or the jump itself if it is\n** unconditional.\n*/\nconst getjumpcontroloffset = function(fs, pc) {\n if (pc >= 1 && lopcodes.testTMode(fs.f.code[pc - 1].opcode))\n return pc - 1;\n else\n return pc;\n};\nconst getjumpcontrol = function(fs, pc) {\n return fs.f.code[getjumpcontroloffset(fs, pc)];\n};\n\n/*\n** Patch destination register for a TESTSET instruction.\n** If instruction in position 'node' is not a TESTSET, return 0 (\"fails\").\n** Otherwise, if 'reg' is not 'NO_REG', set it as the destination\n** register. Otherwise, change instruction to a simple 'TEST' (produces\n** no register value)\n*/\nconst patchtestreg = function(fs, node, reg) {\n let pc = getjumpcontroloffset(fs, node);\n let i = fs.f.code[pc];\n if (i.opcode !== OpCodesI.OP_TESTSET)\n return false; /* cannot patch other instructions */\n if (reg !== lopcodes.NO_REG && reg !== i.B)\n lopcodes.SETARG_A(i, reg);\n else {\n /* no register to put value or register already has the value;\n change instruction to simple test */\n fs.f.code[pc] = lopcodes.CREATE_ABC(OpCodesI.OP_TEST, i.B, 0, i.C);\n }\n return true;\n};\n\n/*\n** Traverse a list of tests ensuring no one produces a value\n*/\nconst removevalues = function(fs, list) {\n for (; list !== NO_JUMP; list = getjump(fs, list))\n patchtestreg(fs, list, lopcodes.NO_REG);\n};\n\n/*\n** Traverse a list of tests, patching their destination address and\n** registers: tests producing values jump to 'vtarget' (and put their\n** values in 'reg'), other tests jump to 'dtarget'.\n*/\nconst patchlistaux = function(fs, list, vtarget, reg, dtarget) {\n while (list !== NO_JUMP) {\n let next = getjump(fs, list);\n if (patchtestreg(fs, list, reg))\n fixjump(fs, list, vtarget);\n else\n fixjump(fs, list, dtarget); /* jump to default target */\n list = next;\n }\n};\n\n/*\n** Ensure all pending jumps to current position are fixed (jumping\n** to current position with no values) and reset list of pending\n** jumps\n*/\nconst dischargejpc = function(fs) {\n patchlistaux(fs, fs.jpc, fs.pc, lopcodes.NO_REG, fs.pc);\n fs.jpc = NO_JUMP;\n};\n\n/*\n** Add elements in 'list' to list of pending jumps to \"here\"\n** (current position)\n*/\nconst luaK_patchtohere = function(fs, list) {\n luaK_getlabel(fs); /* mark \"here\" as a jump target */\n fs.jpc = luaK_concat(fs, fs.jpc, list);\n};\n\n/*\n** Path all jumps in 'list' to jump to 'target'.\n** (The assert means that we cannot fix a jump to a forward address\n** because we only know addresses once code is generated.)\n*/\nconst luaK_patchlist = function(fs, list, target) {\n if (target === fs.pc) /* 'target' is current position? */\n luaK_patchtohere(fs, list); /* add list to pending jumps */\n else {\n lua_assert(target < fs.pc);\n patchlistaux(fs, list, target, lopcodes.NO_REG, target);\n }\n};\n\n/*\n** Path all jumps in 'list' to close upvalues up to given 'level'\n** (The assertion checks that jumps either were closing nothing\n** or were closing higher levels, from inner blocks.)\n*/\nconst luaK_patchclose = function(fs, list, level) {\n level++; /* argument is +1 to reserve 0 as non-op */\n for (; list !== NO_JUMP; list = getjump(fs, list)) {\n let ins = fs.f.code[list];\n lua_assert(ins.opcode === OpCodesI.OP_JMP && (ins.A === 0 || ins.A >= level));\n lopcodes.SETARG_A(ins, level);\n }\n};\n\n/*\n** Emit instruction 'i', checking for array sizes and saving also its\n** line information. Return 'i' position.\n*/\nconst luaK_code = function(fs, i) {\n let f = fs.f;\n dischargejpc(fs); /* 'pc' will change */\n /* put new instruction in code array */\n f.code[fs.pc] = i;\n f.lineinfo[fs.pc] = fs.ls.lastline;\n return fs.pc++;\n};\n\n/*\n** Format and emit an 'iABC' instruction. (Assertions check consistency\n** of parameters versus opcode.)\n*/\nconst luaK_codeABC = function(fs, o, a, b, c) {\n lua_assert(lopcodes.getOpMode(o) === lopcodes.iABC);\n lua_assert(lopcodes.getBMode(o) !== lopcodes.OpArgN || b === 0);\n lua_assert(lopcodes.getCMode(o) !== lopcodes.OpArgN || c === 0);\n lua_assert(a <= lopcodes.MAXARG_A && b <= lopcodes.MAXARG_B && c <= lopcodes.MAXARG_C);\n return luaK_code(fs, lopcodes.CREATE_ABC(o, a, b, c));\n};\n\n/*\n** Format and emit an 'iABx' instruction.\n*/\nconst luaK_codeABx = function(fs, o, a, bc) {\n lua_assert(lopcodes.getOpMode(o) === lopcodes.iABx || lopcodes.getOpMode(o) === lopcodes.iAsBx);\n lua_assert(lopcodes.getCMode(o) === lopcodes.OpArgN);\n lua_assert(a <= lopcodes.MAXARG_A && bc <= lopcodes.MAXARG_Bx);\n return luaK_code(fs, lopcodes.CREATE_ABx(o, a, bc));\n};\n\nconst luaK_codeAsBx = function(fs,o,A,sBx) {\n return luaK_codeABx(fs, o, A, (sBx) + lopcodes.MAXARG_sBx);\n};\n\n/*\n** Emit an \"extra argument\" instruction (format 'iAx')\n*/\nconst codeextraarg = function(fs, a) {\n lua_assert(a <= lopcodes.MAXARG_Ax);\n return luaK_code(fs, lopcodes.CREATE_Ax(OpCodesI.OP_EXTRAARG, a));\n};\n\n/*\n** Emit a \"load constant\" instruction, using either 'OP_LOADK'\n** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX'\n** instruction with \"extra argument\".\n*/\nconst luaK_codek = function(fs, reg, k) {\n if (k <= lopcodes.MAXARG_Bx)\n return luaK_codeABx(fs, OpCodesI.OP_LOADK, reg, k);\n else {\n let p = luaK_codeABx(fs, OpCodesI.OP_LOADKX, reg, 0);\n codeextraarg(fs, k);\n return p;\n }\n};\n\n/*\n** Check register-stack level, keeping track of its maximum size\n** in field 'maxstacksize'\n*/\nconst luaK_checkstack = function(fs, n) {\n let newstack = fs.freereg + n;\n if (newstack > fs.f.maxstacksize) {\n if (newstack >= MAXREGS)\n llex.luaX_syntaxerror(fs.ls, to_luastring(\"function or expression needs too many registers\", true));\n fs.f.maxstacksize = newstack;\n }\n};\n\n/*\n** Reserve 'n' registers in register stack\n*/\nconst luaK_reserveregs = function(fs, n) {\n luaK_checkstack(fs, n);\n fs.freereg += n;\n};\n\n/*\n** Free register 'reg', if it is neither a constant index nor\n** a local variable.\n*/\nconst freereg = function(fs, reg) {\n if (!lopcodes.ISK(reg) && reg >= fs.nactvar) {\n fs.freereg--;\n lua_assert(reg === fs.freereg);\n }\n};\n\n/*\n** Free register used by expression 'e' (if any)\n*/\nconst freeexp = function(fs, e) {\n if (e.k === lparser.expkind.VNONRELOC)\n freereg(fs, e.u.info);\n};\n\n/*\n** Free registers used by expressions 'e1' and 'e2' (if any) in proper\n** order.\n*/\nconst freeexps = function(fs, e1, e2) {\n let r1 = (e1.k === lparser.expkind.VNONRELOC) ? e1.u.info : -1;\n let r2 = (e2.k === lparser.expkind.VNONRELOC) ? e2.u.info : -1;\n if (r1 > r2) {\n freereg(fs, r1);\n freereg(fs, r2);\n }\n else {\n freereg(fs, r2);\n freereg(fs, r1);\n }\n};\n\n\n/*\n** Add constant 'v' to prototype's list of constants (field 'k').\n** Use scanner's table to cache position of constants in constant list\n** and try to reuse constants. Because some values should not be used\n** as keys (nil cannot be a key, integer keys can collapse with float\n** keys), the caller must provide a useful 'key' for indexing the cache.\n*/\nconst addk = function(fs, key, v) {\n let f = fs.f;\n let idx = ltable.luaH_get(fs.L, fs.ls.h, key); /* index scanner table */\n if (idx.ttisinteger()) { /* is there an index there? */\n let k = idx.value;\n /* correct value? (warning: must distinguish floats from integers!) */\n if (k < fs.nk && f.k[k].ttype() === v.ttype() && f.k[k].value === v.value)\n return k; /* reuse index */\n }\n /* constant not found; create a new entry */\n let k = fs.nk;\n ltable.luaH_setfrom(fs.L, fs.ls.h, key, new lobject.TValue(LUA_TNUMINT, k));\n f.k[k] = v;\n fs.nk++;\n return k;\n};\n\n/*\n** Add a string to list of constants and return its index.\n*/\nconst luaK_stringK = function(fs, s) {\n let o = new TValue(LUA_TLNGSTR, s);\n return addk(fs, o, o); /* use string itself as key */\n};\n\n\n/*\n** Add an integer to list of constants and return its index.\n** Integers use userdata as keys to avoid collision with floats with\n** same value.\n*/\nconst luaK_intK = function(fs, n) {\n let k = new TValue(LUA_TLIGHTUSERDATA, n);\n let o = new TValue(LUA_TNUMINT, n);\n return addk(fs, k, o);\n};\n\n/*\n** Add a float to list of constants and return its index.\n*/\nconst luaK_numberK = function(fs, r) {\n let o = new TValue(LUA_TNUMFLT, r);\n return addk(fs, o, o); /* use number itself as key */\n};\n\n\n/*\n** Add a boolean to list of constants and return its index.\n*/\nconst boolK = function(fs, b) {\n let o = new TValue(LUA_TBOOLEAN, b);\n return addk(fs, o, o); /* use boolean itself as key */\n};\n\n\n/*\n** Add nil to list of constants and return its index.\n*/\nconst nilK = function(fs) {\n let v = new TValue(LUA_TNIL, null);\n let k = new TValue(LUA_TTABLE, fs.ls.h);\n /* cannot use nil as key; instead use table itself to represent nil */\n return addk(fs, k, v);\n};\n\n/*\n** Fix an expression to return the number of results 'nresults'.\n** Either 'e' is a multi-ret expression (function call or vararg)\n** or 'nresults' is LUA_MULTRET (as any expression can satisfy that).\n*/\nconst luaK_setreturns = function(fs, e, nresults) {\n let ek = lparser.expkind;\n if (e.k === ek.VCALL) { /* expression is an open function call? */\n lopcodes.SETARG_C(getinstruction(fs, e), nresults + 1);\n }\n else if (e.k === ek.VVARARG) {\n let pc = getinstruction(fs, e);\n lopcodes.SETARG_B(pc, nresults + 1);\n lopcodes.SETARG_A(pc, fs.freereg);\n luaK_reserveregs(fs, 1);\n }\n else lua_assert(nresults === LUA_MULTRET);\n};\n\nconst luaK_setmultret = function(fs, e) {\n luaK_setreturns(fs, e, LUA_MULTRET);\n};\n\n/*\n** Fix an expression to return one result.\n** If expression is not a multi-ret expression (function call or\n** vararg), it already returns one result, so nothing needs to be done.\n** Function calls become VNONRELOC expressions (as its result comes\n** fixed in the base register of the call), while vararg expressions\n** become VRELOCABLE (as OP_VARARG puts its results where it wants).\n** (Calls are created returning one result, so that does not need\n** to be fixed.)\n*/\nconst luaK_setoneret = function(fs, e) {\n let ek = lparser.expkind;\n if (e.k === ek.VCALL) { /* expression is an open function call? */\n /* already returns 1 value */\n lua_assert(getinstruction(fs, e).C === 2);\n e.k = ek.VNONRELOC; /* result has fixed position */\n e.u.info = getinstruction(fs, e).A;\n } else if (e.k === ek.VVARARG) {\n lopcodes.SETARG_B(getinstruction(fs, e), 2);\n e.k = ek.VRELOCABLE; /* can relocate its simple result */\n }\n};\n\n/*\n** Ensure that expression 'e' is not a variable.\n*/\nconst luaK_dischargevars = function(fs, e) {\n let ek = lparser.expkind;\n\n switch (e.k) {\n case ek.VLOCAL: { /* already in a register */\n e.k = ek.VNONRELOC; /* becomes a non-relocatable value */\n break;\n }\n case ek.VUPVAL: { /* move value to some (pending) register */\n e.u.info = luaK_codeABC(fs, OpCodesI.OP_GETUPVAL, 0, e.u.info, 0);\n e.k = ek.VRELOCABLE;\n break;\n }\n case ek.VINDEXED: {\n let op;\n freereg(fs, e.u.ind.idx);\n if (e.u.ind.vt === ek.VLOCAL) { /* is 't' in a register? */\n freereg(fs, e.u.ind.t);\n op = OpCodesI.OP_GETTABLE;\n } else {\n lua_assert(e.u.ind.vt === ek.VUPVAL);\n op = OpCodesI.OP_GETTABUP; /* 't' is in an upvalue */\n }\n e.u.info = luaK_codeABC(fs, op, 0, e.u.ind.t, e.u.ind.idx);\n e.k = ek.VRELOCABLE;\n break;\n }\n case ek.VVARARG: case ek.VCALL: {\n luaK_setoneret(fs, e);\n break;\n }\n default: break; /* there is one value available (somewhere) */\n }\n};\n\nconst code_loadbool = function(fs, A, b, jump) {\n luaK_getlabel(fs); /* those instructions may be jump targets */\n return luaK_codeABC(fs, OpCodesI.OP_LOADBOOL, A, b, jump);\n};\n\n/*\n** Ensures expression value is in register 'reg' (and therefore\n** 'e' will become a non-relocatable expression).\n*/\nconst discharge2reg = function(fs, e, reg) {\n let ek = lparser.expkind;\n luaK_dischargevars(fs, e);\n switch (e.k) {\n case ek.VNIL: {\n luaK_nil(fs, reg, 1);\n break;\n }\n case ek.VFALSE: case ek.VTRUE: {\n luaK_codeABC(fs, OpCodesI.OP_LOADBOOL, reg, e.k === ek.VTRUE, 0);\n break;\n }\n case ek.VK: {\n luaK_codek(fs, reg, e.u.info);\n break;\n }\n case ek.VKFLT: {\n luaK_codek(fs, reg, luaK_numberK(fs, e.u.nval));\n break;\n }\n case ek.VKINT: {\n luaK_codek(fs, reg, luaK_intK(fs, e.u.ival));\n break;\n }\n case ek.VRELOCABLE: {\n let pc = getinstruction(fs, e);\n lopcodes.SETARG_A(pc, reg); /* instruction will put result in 'reg' */\n break;\n }\n case ek.VNONRELOC: {\n if (reg !== e.u.info)\n luaK_codeABC(fs, OpCodesI.OP_MOVE, reg, e.u.info, 0);\n break;\n }\n default: {\n lua_assert(e.k === ek.VJMP);\n return; /* nothing to do... */\n }\n }\n e.u.info = reg;\n e.k = ek.VNONRELOC;\n};\n\n/*\n** Ensures expression value is in any register.\n*/\nconst discharge2anyreg = function(fs, e) {\n if (e.k !== lparser.expkind.VNONRELOC) { /* no fixed register yet? */\n luaK_reserveregs(fs, 1); /* get a register */\n discharge2reg(fs, e, fs.freereg-1); /* put value there */\n }\n};\n\n/*\n** check whether list has any jump that do not produce a value\n** or produce an inverted value\n*/\nconst need_value = function(fs, list) {\n for (; list !== NO_JUMP; list = getjump(fs, list)) {\n let i = getjumpcontrol(fs, list);\n if (i.opcode !== OpCodesI.OP_TESTSET) return true;\n }\n return false; /* not found */\n};\n\n/*\n** Ensures final expression result (including results from its jump\n** lists) is in register 'reg'.\n** If expression has jumps, need to patch these jumps either to\n** its final position or to \"load\" instructions (for those tests\n** that do not produce values).\n*/\nconst exp2reg = function(fs, e, reg) {\n let ek = lparser.expkind;\n discharge2reg(fs, e, reg);\n if (e.k === ek.VJMP) /* expression itself is a test? */\n e.t = luaK_concat(fs, e.t, e.u.info); /* put this jump in 't' list */\n if (hasjumps(e)) {\n let final; /* position after whole expression */\n let p_f = NO_JUMP; /* position of an eventual LOAD false */\n let p_t = NO_JUMP; /* position of an eventual LOAD true */\n if (need_value(fs, e.t) || need_value(fs, e.f)) {\n let fj = (e.k === ek.VJMP) ? NO_JUMP : luaK_jump(fs);\n p_f = code_loadbool(fs, reg, 0, 1);\n p_t = code_loadbool(fs, reg, 1, 0);\n luaK_patchtohere(fs, fj);\n }\n final = luaK_getlabel(fs);\n patchlistaux(fs, e.f, final, reg, p_f);\n patchlistaux(fs, e.t, final, reg, p_t);\n }\n e.f = e.t = NO_JUMP;\n e.u.info = reg;\n e.k = ek.VNONRELOC;\n};\n\n/*\n** Ensures final expression result (including results from its jump\n** lists) is in next available register.\n*/\nconst luaK_exp2nextreg = function(fs, e) {\n luaK_dischargevars(fs, e);\n freeexp(fs, e);\n luaK_reserveregs(fs, 1);\n exp2reg(fs, e, fs.freereg - 1);\n};\n\n\n/*\n** Ensures final expression result (including results from its jump\n** lists) is in some (any) register and return that register.\n*/\nconst luaK_exp2anyreg = function(fs, e) {\n luaK_dischargevars(fs, e);\n if (e.k === lparser.expkind.VNONRELOC) { /* expression already has a register? */\n if (!hasjumps(e)) /* no jumps? */\n return e.u.info; /* result is already in a register */\n if (e.u.info >= fs.nactvar) { /* reg. is not a local? */\n exp2reg(fs, e, e.u.info); /* put final result in it */\n return e.u.info;\n }\n }\n luaK_exp2nextreg(fs, e); /* otherwise, use next available register */\n return e.u.info;\n};\n\n/*\n** Ensures final expression result is either in a register or in an\n** upvalue.\n*/\nconst luaK_exp2anyregup = function(fs, e) {\n if (e.k !== lparser.expkind.VUPVAL || hasjumps(e))\n luaK_exp2anyreg(fs, e);\n};\n\n/*\n** Ensures final expression result is either in a register or it is\n** a constant.\n*/\nconst luaK_exp2val = function(fs, e) {\n if (hasjumps(e))\n luaK_exp2anyreg(fs, e);\n else\n luaK_dischargevars(fs, e);\n};\n\n/*\n** Ensures final expression result is in a valid R/K index\n** (that is, it is either in a register or in 'k' with an index\n** in the range of R/K indices).\n** Returns R/K index.\n*/\nconst luaK_exp2RK = function(fs, e) {\n let ek = lparser.expkind;\n let vk = false;\n luaK_exp2val(fs, e);\n switch (e.k) { /* move constants to 'k' */\n case ek.VTRUE: e.u.info = boolK(fs, true); vk = true; break;\n case ek.VFALSE: e.u.info = boolK(fs, false); vk = true; break;\n case ek.VNIL: e.u.info = nilK(fs); vk = true; break;\n case ek.VKINT: e.u.info = luaK_intK(fs, e.u.ival); vk = true; break;\n case ek.VKFLT: e.u.info = luaK_numberK(fs, e.u.nval); vk = true; break;\n case ek.VK: vk = true; break;\n default: break;\n }\n\n if (vk) {\n e.k = ek.VK;\n if (e.u.info <= lopcodes.MAXINDEXRK) /* constant fits in 'argC'? */\n return lopcodes.RKASK(e.u.info);\n }\n\n /* not a constant in the right range: put it in a register */\n return luaK_exp2anyreg(fs, e);\n};\n\n/*\n** Generate code to store result of expression 'ex' into variable 'var'.\n*/\nconst luaK_storevar = function(fs, vr, ex) {\n let ek = lparser.expkind;\n switch (vr.k) {\n case ek.VLOCAL: {\n freeexp(fs, ex);\n exp2reg(fs, ex, vr.u.info); /* compute 'ex' into proper place */\n return;\n }\n case ek.VUPVAL: {\n let e = luaK_exp2anyreg(fs, ex);\n luaK_codeABC(fs, OpCodesI.OP_SETUPVAL, e, vr.u.info, 0);\n break;\n }\n case ek.VINDEXED: {\n let op = (vr.u.ind.vt === ek.VLOCAL) ? OpCodesI.OP_SETTABLE : OpCodesI.OP_SETTABUP;\n let e = luaK_exp2RK(fs, ex);\n luaK_codeABC(fs, op, vr.u.ind.t, vr.u.ind.idx, e);\n break;\n }\n }\n freeexp(fs, ex);\n};\n\n\n/*\n** Emit SELF instruction (convert expression 'e' into 'e:key(e,').\n*/\nconst luaK_self = function(fs, e, key) {\n luaK_exp2anyreg(fs, e);\n let ereg = e.u.info; /* register where 'e' was placed */\n freeexp(fs, e);\n e.u.info = fs.freereg; /* base register for op_self */\n e.k = lparser.expkind.VNONRELOC; /* self expression has a fixed register */\n luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */\n luaK_codeABC(fs, OpCodesI.OP_SELF, e.u.info, ereg, luaK_exp2RK(fs, key));\n freeexp(fs, key);\n};\n\n/*\n** Negate condition 'e' (where 'e' is a comparison).\n*/\nconst negatecondition = function(fs, e) {\n let pc = getjumpcontrol(fs, e.u.info);\n lua_assert(lopcodes.testTMode(pc.opcode) && pc.opcode !== OpCodesI.OP_TESTSET && pc.opcode !== OpCodesI.OP_TEST);\n lopcodes.SETARG_A(pc, !(pc.A));\n};\n\n/*\n** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond'\n** is true, code will jump if 'e' is true.) Return jump position.\n** Optimize when 'e' is 'not' something, inverting the condition\n** and removing the 'not'.\n*/\nconst jumponcond = function(fs, e, cond) {\n if (e.k === lparser.expkind.VRELOCABLE) {\n let ie = getinstruction(fs, e);\n if (ie.opcode === OpCodesI.OP_NOT) {\n fs.pc--; /* remove previous OP_NOT */\n return condjump(fs, OpCodesI.OP_TEST, ie.B, 0, !cond);\n }\n /* else go through */\n }\n discharge2anyreg(fs, e);\n freeexp(fs, e);\n return condjump(fs, OpCodesI.OP_TESTSET, lopcodes.NO_REG, e.u.info, cond);\n};\n\n/*\n** Emit code to go through if 'e' is true, jump otherwise.\n*/\nconst luaK_goiftrue = function(fs, e) {\n let ek = lparser.expkind;\n let pc; /* pc of new jump */\n luaK_dischargevars(fs, e);\n switch (e.k) {\n case ek.VJMP: { /* condition? */\n negatecondition(fs, e); /* jump when it is false */\n pc = e.u.info; /* save jump position */\n break;\n }\n case ek.VK: case ek.VKFLT: case ek.VKINT: case ek.VTRUE: {\n pc = NO_JUMP; /* always true; do nothing */\n break;\n }\n default: {\n pc = jumponcond(fs, e, 0); /* jump when false */\n break;\n }\n }\n e.f = luaK_concat(fs, e.f, pc); /* insert new jump in false list */\n luaK_patchtohere(fs, e.t); /* true list jumps to here (to go through) */\n e.t = NO_JUMP;\n};\n\n/*\n** Emit code to go through if 'e' is false, jump otherwise.\n*/\nconst luaK_goiffalse = function(fs, e) {\n let ek = lparser.expkind;\n let pc; /* pc of new jump */\n luaK_dischargevars(fs, e);\n switch (e.k) {\n case ek.VJMP: {\n pc = e.u.info; /* already jump if true */\n break;\n }\n case ek.VNIL: case ek.VFALSE: {\n pc = NO_JUMP; /* always false; do nothing */\n break;\n }\n default: {\n pc = jumponcond(fs, e, 1); /* jump if true */\n break;\n }\n }\n e.t = luaK_concat(fs, e.t, pc); /* insert new jump in 't' list */\n luaK_patchtohere(fs, e.f); /* false list jumps to here (to go through) */\n e.f = NO_JUMP;\n};\n\n/*\n** Code 'not e', doing constant folding.\n*/\nconst codenot = function(fs, e) {\n let ek = lparser.expkind;\n luaK_dischargevars(fs, e);\n switch (e.k) {\n case ek.VNIL: case ek.VFALSE: {\n e.k = ek.VTRUE; /* true === not nil === not false */\n break;\n }\n case ek.VK: case ek.VKFLT: case ek.VKINT: case ek.VTRUE: {\n e.k = ek.VFALSE; /* false === not \"x\" === not 0.5 === not 1 === not true */\n break;\n }\n case ek.VJMP: {\n negatecondition(fs, e);\n break;\n }\n case ek.VRELOCABLE:\n case ek.VNONRELOC: {\n discharge2anyreg(fs, e);\n freeexp(fs, e);\n e.u.info = luaK_codeABC(fs, OpCodesI.OP_NOT, 0, e.u.info, 0);\n e.k = ek.VRELOCABLE;\n break;\n }\n }\n /* interchange true and false lists */\n { let temp = e.f; e.f = e.t; e.t = temp; }\n removevalues(fs, e.f); /* values are useless when negated */\n removevalues(fs, e.t);\n};\n\n/*\n** Create expression 't[k]'. 't' must have its final result already in a\n** register or upvalue.\n*/\nconst luaK_indexed = function(fs, t, k) {\n let ek = lparser.expkind;\n lua_assert(!hasjumps(t) && (lparser.vkisinreg(t.k) || t.k === ek.VUPVAL));\n t.u.ind.t = t.u.info; /* register or upvalue index */\n t.u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */\n t.u.ind.vt = (t.k === ek.VUPVAL) ? ek.VUPVAL : ek.VLOCAL;\n t.k = ek.VINDEXED;\n};\n\n/*\n** Return false if folding can raise an error.\n** Bitwise operations need operands convertible to integers; division\n** operations cannot have 0 as divisor.\n*/\nconst validop = function(op, v1, v2) {\n switch (op) {\n case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:\n case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */\n return (lvm.tointeger(v1) !== false && lvm.tointeger(v2) !== false);\n }\n case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */\n return (v2.value !== 0);\n default: return 1; /* everything else is valid */\n }\n};\n\n/*\n** Try to \"constant-fold\" an operation; return 1 iff successful.\n** (In this case, 'e1' has the final result.)\n*/\nconst constfolding = function(op, e1, e2) {\n let ek = lparser.expkind;\n let v1, v2;\n if (!(v1 = tonumeral(e1, true)) || !(v2 = tonumeral(e2, true)) || !validop(op, v1, v2))\n return 0; /* non-numeric operands or not safe to fold */\n let res = new TValue(); /* FIXME */\n lobject.luaO_arith(null, op, v1, v2, res); /* does operation */\n if (res.ttisinteger()) {\n e1.k = ek.VKINT;\n e1.u.ival = res.value;\n }\n else { /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */\n let n = res.value;\n if (isNaN(n) || n === 0)\n return false;\n e1.k = ek.VKFLT;\n e1.u.nval = n;\n }\n return true;\n};\n\n/*\n** Emit code for unary expressions that \"produce values\"\n** (everything but 'not').\n** Expression to produce final result will be encoded in 'e'.\n*/\nconst codeunexpval = function(fs, op, e, line) {\n let r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */\n freeexp(fs, e);\n e.u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */\n e.k = lparser.expkind.VRELOCABLE; /* all those operations are relocatable */\n luaK_fixline(fs, line);\n};\n\n/*\n** Emit code for binary expressions that \"produce values\"\n** (everything but logical operators 'and'/'or' and comparison\n** operators).\n** Expression to produce final result will be encoded in 'e1'.\n** Because 'luaK_exp2RK' can free registers, its calls must be\n** in \"stack order\" (that is, first on 'e2', which may have more\n** recent registers to be released).\n*/\nconst codebinexpval = function(fs, op, e1, e2, line) {\n let rk2 = luaK_exp2RK(fs, e2); /* both operands are \"RK\" */\n let rk1 = luaK_exp2RK(fs, e1);\n freeexps(fs, e1, e2);\n e1.u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */\n e1.k = lparser.expkind.VRELOCABLE; /* all those operations are relocatable */\n luaK_fixline(fs, line);\n};\n\n\n/*\n** Emit code for comparisons.\n** 'e1' was already put in R/K form by 'luaK_infix'.\n*/\nconst codecomp = function(fs, opr, e1, e2) {\n let ek = lparser.expkind;\n\n let rk1;\n if (e1.k === ek.VK)\n rk1 = lopcodes.RKASK(e1.u.info);\n else {\n lua_assert(e1.k === ek.VNONRELOC);\n rk1 = e1.u.info;\n }\n\n let rk2 = luaK_exp2RK(fs, e2);\n freeexps(fs, e1, e2);\n switch (opr) {\n case BinOpr.OPR_NE: { /* '(a ~= b)' ==> 'not (a === b)' */\n e1.u.info = condjump(fs, OpCodesI.OP_EQ, 0, rk1, rk2);\n break;\n }\n case BinOpr.OPR_GT: case BinOpr.OPR_GE: {\n /* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */\n let op = (opr - BinOpr.OPR_NE) + OpCodesI.OP_EQ;\n e1.u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */\n break;\n }\n default: { /* '==', '<', '<=' use their own opcodes */\n let op = (opr - BinOpr.OPR_EQ) + OpCodesI.OP_EQ;\n e1.u.info = condjump(fs, op, 1, rk1, rk2);\n break;\n }\n }\n e1.k = ek.VJMP;\n};\n\n/*\n** Apply prefix operation 'op' to expression 'e'.\n*/\nconst luaK_prefix = function(fs, op, e, line) {\n let ef = new lparser.expdesc();\n ef.k = lparser.expkind.VKINT;\n ef.u.ival = ef.u.nval = ef.u.info = 0;\n ef.t = NO_JUMP;\n ef.f = NO_JUMP;\n switch (op) {\n case UnOpr.OPR_MINUS: case UnOpr.OPR_BNOT: /* use 'ef' as fake 2nd operand */\n if (constfolding(op + LUA_OPUNM, e, ef))\n break;\n /* FALLTHROUGH */\n case UnOpr.OPR_LEN:\n codeunexpval(fs, op + OpCodesI.OP_UNM, e, line);\n break;\n case UnOpr.OPR_NOT: codenot(fs, e); break;\n }\n};\n\n/*\n** Process 1st operand 'v' of binary operation 'op' before reading\n** 2nd operand.\n*/\nconst luaK_infix = function(fs, op, v) {\n switch (op) {\n case BinOpr.OPR_AND: {\n luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */\n break;\n }\n case BinOpr.OPR_OR: {\n luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */\n break;\n }\n case BinOpr.OPR_CONCAT: {\n luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */\n break;\n }\n case BinOpr.OPR_ADD: case BinOpr.OPR_SUB:\n case BinOpr.OPR_MUL: case BinOpr.OPR_DIV: case BinOpr.OPR_IDIV:\n case BinOpr.OPR_MOD: case BinOpr.OPR_POW:\n case BinOpr.OPR_BAND: case BinOpr.OPR_BOR: case BinOpr.OPR_BXOR:\n case BinOpr.OPR_SHL: case BinOpr.OPR_SHR: {\n if (!tonumeral(v, false))\n luaK_exp2RK(fs, v);\n /* else keep numeral, which may be folded with 2nd operand */\n break;\n }\n default: {\n luaK_exp2RK(fs, v);\n break;\n }\n }\n};\n\n/*\n** Finalize code for binary operation, after reading 2nd operand.\n** For '(a .. b .. c)' (which is '(a .. (b .. c))', because\n** concatenation is right associative), merge second CONCAT into first\n** one.\n*/\nconst luaK_posfix = function(fs, op, e1, e2, line) {\n let ek = lparser.expkind;\n switch (op) {\n case BinOpr.OPR_AND: {\n lua_assert(e1.t === NO_JUMP); /* list closed by 'luK_infix' */\n luaK_dischargevars(fs, e2);\n e2.f = luaK_concat(fs, e2.f, e1.f);\n e1.to(e2);\n break;\n }\n case BinOpr.OPR_OR: {\n lua_assert(e1.f === NO_JUMP); /* list closed by 'luK_infix' */\n luaK_dischargevars(fs, e2);\n e2.t = luaK_concat(fs, e2.t, e1.t);\n e1.to(e2);\n break;\n }\n case BinOpr.OPR_CONCAT: {\n luaK_exp2val(fs, e2);\n let ins = getinstruction(fs, e2);\n if (e2.k === ek.VRELOCABLE && ins.opcode === OpCodesI.OP_CONCAT) {\n lua_assert(e1.u.info === ins.B - 1);\n freeexp(fs, e1);\n lopcodes.SETARG_B(ins, e1.u.info);\n e1.k = ek.VRELOCABLE; e1.u.info = e2.u.info;\n }\n else {\n luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */\n codebinexpval(fs, OpCodesI.OP_CONCAT, e1, e2, line);\n }\n break;\n }\n case BinOpr.OPR_ADD: case BinOpr.OPR_SUB: case BinOpr.OPR_MUL: case BinOpr.OPR_DIV:\n case BinOpr.OPR_IDIV: case BinOpr.OPR_MOD: case BinOpr.OPR_POW:\n case BinOpr.OPR_BAND: case BinOpr.OPR_BOR: case BinOpr.OPR_BXOR:\n case BinOpr.OPR_SHL: case BinOpr.OPR_SHR: {\n if (!constfolding(op + LUA_OPADD, e1, e2))\n codebinexpval(fs, op + OpCodesI.OP_ADD, e1, e2, line);\n break;\n }\n case BinOpr.OPR_EQ: case BinOpr.OPR_LT: case BinOpr.OPR_LE:\n case BinOpr.OPR_NE: case BinOpr.OPR_GT: case BinOpr.OPR_GE: {\n codecomp(fs, op, e1, e2);\n break;\n }\n }\n\n return e1;\n};\n\n/*\n** Change line information associated with current position.\n*/\nconst luaK_fixline = function(fs, line) {\n fs.f.lineinfo[fs.pc - 1] = line;\n};\n\n/*\n** Emit a SETLIST instruction.\n** 'base' is register that keeps table;\n** 'nelems' is #table plus those to be stored now;\n** 'tostore' is number of values (in registers 'base + 1',...) to add to\n** table (or LUA_MULTRET to add up to stack top).\n*/\nconst luaK_setlist = function(fs, base, nelems, tostore) {\n let c = (nelems - 1)/lopcodes.LFIELDS_PER_FLUSH + 1;\n let b = (tostore === LUA_MULTRET) ? 0 : tostore;\n lua_assert(tostore !== 0 && tostore <= lopcodes.LFIELDS_PER_FLUSH);\n if (c <= lopcodes.MAXARG_C)\n luaK_codeABC(fs, OpCodesI.OP_SETLIST, base, b, c);\n else if (c <= lopcodes.MAXARG_Ax) {\n luaK_codeABC(fs, OpCodesI.OP_SETLIST, base, b, 0);\n codeextraarg(fs, c);\n }\n else\n llex.luaX_syntaxerror(fs.ls, to_luastring(\"constructor too long\", true));\n fs.freereg = base + 1; /* free registers with list values */\n};\n\n\nmodule.exports.BinOpr = BinOpr;\nmodule.exports.NO_JUMP = NO_JUMP;\nmodule.exports.UnOpr = UnOpr;\nmodule.exports.getinstruction = getinstruction;\nmodule.exports.luaK_checkstack = luaK_checkstack;\nmodule.exports.luaK_code = luaK_code;\nmodule.exports.luaK_codeABC = luaK_codeABC;\nmodule.exports.luaK_codeABx = luaK_codeABx;\nmodule.exports.luaK_codeAsBx = luaK_codeAsBx;\nmodule.exports.luaK_codek = luaK_codek;\nmodule.exports.luaK_concat = luaK_concat;\nmodule.exports.luaK_dischargevars = luaK_dischargevars;\nmodule.exports.luaK_exp2RK = luaK_exp2RK;\nmodule.exports.luaK_exp2anyreg = luaK_exp2anyreg;\nmodule.exports.luaK_exp2anyregup = luaK_exp2anyregup;\nmodule.exports.luaK_exp2nextreg = luaK_exp2nextreg;\nmodule.exports.luaK_exp2val = luaK_exp2val;\nmodule.exports.luaK_fixline = luaK_fixline;\nmodule.exports.luaK_getlabel = luaK_getlabel;\nmodule.exports.luaK_goiffalse = luaK_goiffalse;\nmodule.exports.luaK_goiftrue = luaK_goiftrue;\nmodule.exports.luaK_indexed = luaK_indexed;\nmodule.exports.luaK_infix = luaK_infix;\nmodule.exports.luaK_intK = luaK_intK;\nmodule.exports.luaK_jump = luaK_jump;\nmodule.exports.luaK_jumpto = luaK_jumpto;\nmodule.exports.luaK_nil = luaK_nil;\nmodule.exports.luaK_numberK = luaK_numberK;\nmodule.exports.luaK_patchclose = luaK_patchclose;\nmodule.exports.luaK_patchlist = luaK_patchlist;\nmodule.exports.luaK_patchtohere = luaK_patchtohere;\nmodule.exports.luaK_posfix = luaK_posfix;\nmodule.exports.luaK_prefix = luaK_prefix;\nmodule.exports.luaK_reserveregs = luaK_reserveregs;\nmodule.exports.luaK_ret = luaK_ret;\nmodule.exports.luaK_self = luaK_self;\nmodule.exports.luaK_setlist = luaK_setlist;\nmodule.exports.luaK_setmultret = luaK_setmultret;\nmodule.exports.luaK_setoneret = luaK_setoneret;\nmodule.exports.luaK_setreturns = luaK_setreturns;\nmodule.exports.luaK_storevar = luaK_storevar;\nmodule.exports.luaK_stringK = luaK_stringK;\n","\"use strict\";\n\nconst {\n LUA_SIGNATURE,\n constant_types: {\n LUA_TBOOLEAN,\n LUA_TLNGSTR,\n LUA_TNIL,\n LUA_TNUMFLT,\n LUA_TNUMINT,\n LUA_TSHRSTR\n },\n thread_status: { LUA_ERRSYNTAX },\n is_luastring,\n luastring_eq,\n to_luastring\n} = require('./defs.js');\nconst ldo = require('./ldo.js');\nconst lfunc = require('./lfunc.js');\nconst lobject = require('./lobject.js');\nconst {\n MAXARG_sBx,\n POS_A,\n POS_Ax,\n POS_B,\n POS_Bx,\n POS_C,\n POS_OP,\n SIZE_A,\n SIZE_Ax,\n SIZE_B,\n SIZE_Bx,\n SIZE_C,\n SIZE_OP\n} = require('./lopcodes.js');\nconst { lua_assert } = require(\"./llimits.js\");\nconst { luaS_bless } = require('./lstring.js');\nconst {\n luaZ_read,\n ZIO\n} = require('./lzio.js');\n\nlet LUAC_DATA = [0x19, 0x93, 13, 10, 0x1a, 10];\n\nclass BytecodeParser {\n\n constructor(L, Z, name) {\n this.intSize = 4;\n this.size_tSize = 4;\n this.instructionSize = 4;\n this.integerSize = 4;\n this.numberSize = 8;\n\n lua_assert(Z instanceof ZIO, \"BytecodeParser only operates on a ZIO\");\n lua_assert(is_luastring(name));\n\n if (name[0] === 64 /* ('@').charCodeAt(0) */ || name[0] === 61 /* ('=').charCodeAt(0) */)\n this.name = name.subarray(1);\n else if (name[0] == LUA_SIGNATURE[0])\n this.name = to_luastring(\"binary string\", true);\n else\n this.name = name;\n\n this.L = L;\n this.Z = Z;\n\n // Used to do buffer to number conversions\n this.arraybuffer = new ArrayBuffer(\n Math.max(this.intSize, this.size_tSize, this.instructionSize, this.integerSize, this.numberSize)\n );\n this.dv = new DataView(this.arraybuffer);\n this.u8 = new Uint8Array(this.arraybuffer);\n }\n\n read(size) {\n let u8 = new Uint8Array(size);\n if(luaZ_read(this.Z, u8, 0, size) !== 0)\n this.error(\"truncated\");\n return u8;\n }\n\n LoadByte() {\n if (luaZ_read(this.Z, this.u8, 0, 1) !== 0)\n this.error(\"truncated\");\n return this.u8[0];\n }\n\n LoadInt() {\n if (luaZ_read(this.Z, this.u8, 0, this.intSize) !== 0)\n this.error(\"truncated\");\n return this.dv.getInt32(0, true);\n }\n\n LoadNumber() {\n if (luaZ_read(this.Z, this.u8, 0, this.numberSize) !== 0)\n this.error(\"truncated\");\n return this.dv.getFloat64(0, true);\n }\n\n LoadInteger() {\n if (luaZ_read(this.Z, this.u8, 0, this.integerSize) !== 0)\n this.error(\"truncated\");\n return this.dv.getInt32(0, true);\n }\n\n LoadSize_t() {\n return this.LoadInteger();\n }\n\n LoadString() {\n let size = this.LoadByte();\n if (size === 0xFF)\n size = this.LoadSize_t();\n if (size === 0)\n return null;\n return luaS_bless(this.L, this.read(size-1));\n }\n\n /* creates a mask with 'n' 1 bits at position 'p' */\n static MASK1(n, p) {\n return ((~((~0)<<(n)))<<(p));\n }\n\n LoadCode(f) {\n let n = this.LoadInt();\n let p = BytecodeParser;\n\n for (let i = 0; i < n; i++) {\n if (luaZ_read(this.Z, this.u8, 0, this.instructionSize) !== 0)\n this.error(\"truncated\");\n let ins = this.dv.getUint32(0, true);\n f.code[i] = {\n code: ins,\n opcode: (ins >> POS_OP) & p.MASK1(SIZE_OP, 0),\n A: (ins >> POS_A) & p.MASK1(SIZE_A, 0),\n B: (ins >> POS_B) & p.MASK1(SIZE_B, 0),\n C: (ins >> POS_C) & p.MASK1(SIZE_C, 0),\n Bx: (ins >> POS_Bx) & p.MASK1(SIZE_Bx, 0),\n Ax: (ins >> POS_Ax) & p.MASK1(SIZE_Ax, 0),\n sBx: ((ins >> POS_Bx) & p.MASK1(SIZE_Bx, 0)) - MAXARG_sBx\n };\n }\n }\n\n LoadConstants(f) {\n let n = this.LoadInt();\n\n for (let i = 0; i < n; i++) {\n let t = this.LoadByte();\n\n switch (t) {\n case LUA_TNIL:\n f.k.push(new lobject.TValue(LUA_TNIL, null));\n break;\n case LUA_TBOOLEAN:\n f.k.push(new lobject.TValue(LUA_TBOOLEAN, this.LoadByte() !== 0));\n break;\n case LUA_TNUMFLT:\n f.k.push(new lobject.TValue(LUA_TNUMFLT, this.LoadNumber()));\n break;\n case LUA_TNUMINT:\n f.k.push(new lobject.TValue(LUA_TNUMINT, this.LoadInteger()));\n break;\n case LUA_TSHRSTR:\n case LUA_TLNGSTR:\n f.k.push(new lobject.TValue(LUA_TLNGSTR, this.LoadString()));\n break;\n default:\n this.error(`unrecognized constant '${t}'`);\n }\n }\n }\n\n LoadProtos(f) {\n let n = this.LoadInt();\n\n for (let i = 0; i < n; i++) {\n f.p[i] = new lfunc.Proto(this.L);\n this.LoadFunction(f.p[i], f.source);\n }\n }\n\n LoadUpvalues(f) {\n let n = this.LoadInt();\n\n for (let i = 0; i < n; i++) {\n f.upvalues[i] = {\n name: null,\n instack: this.LoadByte(),\n idx: this.LoadByte()\n };\n }\n }\n\n LoadDebug(f) {\n let n = this.LoadInt();\n for (let i = 0; i < n; i++)\n f.lineinfo[i] = this.LoadInt();\n\n n = this.LoadInt();\n for (let i = 0; i < n; i++) {\n f.locvars[i] = {\n varname: this.LoadString(),\n startpc: this.LoadInt(),\n endpc: this.LoadInt()\n };\n }\n\n n = this.LoadInt();\n for (let i = 0; i < n; i++) {\n f.upvalues[i].name = this.LoadString();\n }\n }\n\n LoadFunction(f, psource) {\n f.source = this.LoadString();\n if (f.source === null) /* no source in dump? */\n f.source = psource; /* reuse parent's source */\n f.linedefined = this.LoadInt();\n f.lastlinedefined = this.LoadInt();\n f.numparams = this.LoadByte();\n f.is_vararg = this.LoadByte() !== 0;\n f.maxstacksize = this.LoadByte();\n this.LoadCode(f);\n this.LoadConstants(f);\n this.LoadUpvalues(f);\n this.LoadProtos(f);\n this.LoadDebug(f);\n }\n\n checkliteral(s, msg) {\n let buff = this.read(s.length);\n if (!luastring_eq(buff, s))\n this.error(msg);\n }\n\n checkHeader() {\n this.checkliteral(LUA_SIGNATURE.subarray(1), \"not a\"); /* 1st char already checked */\n\n if (this.LoadByte() !== 0x53)\n this.error(\"version mismatch in\");\n\n if (this.LoadByte() !== 0)\n this.error(\"format mismatch in\");\n\n this.checkliteral(LUAC_DATA, \"corrupted\");\n\n this.intSize = this.LoadByte();\n this.size_tSize = this.LoadByte();\n this.instructionSize = this.LoadByte();\n this.integerSize = this.LoadByte();\n this.numberSize = this.LoadByte();\n\n this.checksize(this.intSize, 4, \"int\");\n this.checksize(this.size_tSize, 4, \"size_t\");\n this.checksize(this.instructionSize, 4, \"instruction\");\n this.checksize(this.integerSize, 4, \"integer\");\n this.checksize(this.numberSize, 8, \"number\");\n\n if (this.LoadInteger() !== 0x5678)\n this.error(\"endianness mismatch in\");\n\n if (this.LoadNumber() !== 370.5)\n this.error(\"float format mismatch in\");\n\n }\n\n error(why) {\n lobject.luaO_pushfstring(this.L, to_luastring(\"%s: %s precompiled chunk\"), this.name, to_luastring(why));\n ldo.luaD_throw(this.L, LUA_ERRSYNTAX);\n }\n\n checksize(byte, size, tname) {\n if (byte !== size)\n this.error(`${tname} size mismatch in`);\n }\n}\n\nconst luaU_undump = function(L, Z, name) {\n let S = new BytecodeParser(L, Z, name);\n S.checkHeader();\n let cl = lfunc.luaF_newLclosure(L, S.LoadByte());\n ldo.luaD_inctop(L);\n L.stack[L.top-1].setclLvalue(cl);\n cl.p = new lfunc.Proto(L);\n S.LoadFunction(cl.p, null);\n lua_assert(cl.nupvalues === cl.p.upvalues.length);\n /* luai_verifycode */\n return cl;\n};\n\nmodule.exports.luaU_undump = luaU_undump;\n","\"use strict\";\n\nconst {\n LUA_SIGNATURE,\n LUA_VERSION_MAJOR,\n LUA_VERSION_MINOR,\n constant_types: {\n LUA_TBOOLEAN,\n LUA_TLNGSTR,\n LUA_TNIL,\n LUA_TNUMFLT,\n LUA_TNUMINT,\n LUA_TSHRSTR\n },\n luastring_of\n} = require('./defs.js');\n\nconst LUAC_DATA = luastring_of(25, 147, 13, 10, 26, 10);\nconst LUAC_INT = 0x5678;\nconst LUAC_NUM = 370.5;\nconst LUAC_VERSION = Number(LUA_VERSION_MAJOR) * 16 + Number(LUA_VERSION_MINOR);\nconst LUAC_FORMAT = 0; /* this is the official format */\n\nclass DumpState {\n constructor() {\n this.L = null;\n this.write = null;\n this.data = null;\n this.strip = NaN;\n this.status = NaN;\n }\n}\n\nconst DumpBlock = function(b, size, D) {\n if (D.status === 0 && size > 0)\n D.status = D.writer(D.L, b, size, D.data);\n};\n\nconst DumpByte = function(y, D) {\n DumpBlock(luastring_of(y), 1, D);\n};\n\nconst DumpInt = function(x, D) {\n let ab = new ArrayBuffer(4);\n let dv = new DataView(ab);\n dv.setInt32(0, x, true);\n let t = new Uint8Array(ab);\n DumpBlock(t, 4, D);\n};\n\nconst DumpInteger = function(x, D) {\n let ab = new ArrayBuffer(4);\n let dv = new DataView(ab);\n dv.setInt32(0, x, true);\n let t = new Uint8Array(ab);\n DumpBlock(t, 4, D);\n};\n\nconst DumpNumber = function(x, D) {\n let ab = new ArrayBuffer(8);\n let dv = new DataView(ab);\n dv.setFloat64(0, x, true);\n let t = new Uint8Array(ab);\n DumpBlock(t, 8, D);\n};\n\nconst DumpString = function(s, D) {\n if (s === null)\n DumpByte(0, D);\n else {\n let size = s.tsslen() + 1;\n let str = s.getstr();\n if (size < 0xFF)\n DumpByte(size, D);\n else {\n DumpByte(0xFF, D);\n DumpInteger(size, D);\n }\n DumpBlock(str, size - 1, D); /* no need to save '\\0' */\n }\n};\n\nconst DumpCode = function(f, D) {\n let s = f.code.map(e => e.code);\n DumpInt(s.length, D);\n\n for (let i = 0; i < s.length; i++)\n DumpInt(s[i], D);\n};\n\nconst DumpConstants = function(f, D) {\n let n = f.k.length;\n DumpInt(n, D);\n for (let i = 0; i < n; i++) {\n let o = f.k[i];\n DumpByte(o.ttype(), D);\n switch (o.ttype()) {\n case LUA_TNIL:\n break;\n case LUA_TBOOLEAN:\n DumpByte(o.value ? 1 : 0, D);\n break;\n case LUA_TNUMFLT:\n DumpNumber(o.value, D);\n break;\n case LUA_TNUMINT:\n DumpInteger(o.value, D);\n break;\n case LUA_TSHRSTR:\n case LUA_TLNGSTR:\n DumpString(o.tsvalue(), D);\n break;\n }\n }\n};\n\nconst DumpProtos = function(f, D) {\n let n = f.p.length;\n DumpInt(n, D);\n for (let i = 0; i < n; i++)\n DumpFunction(f.p[i], f.source, D);\n};\n\nconst DumpUpvalues = function(f, D) {\n let n = f.upvalues.length;\n DumpInt(n, D);\n for (let i = 0; i < n; i++) {\n DumpByte(f.upvalues[i].instack ? 1 : 0, D);\n DumpByte(f.upvalues[i].idx, D);\n }\n};\n\nconst DumpDebug = function(f, D) {\n let n = D.strip ? 0 : f.lineinfo.length;\n DumpInt(n, D);\n for (let i = 0; i < n; i++)\n DumpInt(f.lineinfo[i], D);\n n = D.strip ? 0 : f.locvars.length;\n DumpInt(n, D);\n for (let i = 0; i < n; i++) {\n DumpString(f.locvars[i].varname, D);\n DumpInt(f.locvars[i].startpc, D);\n DumpInt(f.locvars[i].endpc, D);\n }\n n = D.strip ? 0 : f.upvalues.length;\n DumpInt(n, D);\n for (let i = 0; i < n; i++)\n DumpString(f.upvalues[i].name, D);\n};\n\nconst DumpFunction = function(f, psource, D) {\n if (D.strip || f.source === psource)\n DumpString(null, D); /* no debug info or same source as its parent */\n else\n DumpString(f.source, D);\n DumpInt(f.linedefined, D);\n DumpInt(f.lastlinedefined, D);\n DumpByte(f.numparams, D);\n DumpByte(f.is_vararg?1:0, D);\n DumpByte(f.maxstacksize, D);\n DumpCode(f, D);\n DumpConstants(f, D);\n DumpUpvalues(f, D);\n DumpProtos(f, D);\n DumpDebug(f, D);\n};\n\nconst DumpHeader = function(D) {\n DumpBlock(LUA_SIGNATURE, LUA_SIGNATURE.length, D);\n DumpByte(LUAC_VERSION, D);\n DumpByte(LUAC_FORMAT, D);\n DumpBlock(LUAC_DATA, LUAC_DATA.length, D);\n DumpByte(4, D); // intSize\n DumpByte(4, D); // size_tSize\n DumpByte(4, D); // instructionSize\n DumpByte(4, D); // integerSize\n DumpByte(8, D); // numberSize\n DumpInteger(LUAC_INT, D);\n DumpNumber(LUAC_NUM, D);\n};\n\n/*\n** dump Lua function as precompiled chunk\n*/\nconst luaU_dump = function(L, f, w, data, strip) {\n let D = new DumpState();\n D.L = L;\n D.writer = w;\n D.data = data;\n D.strip = strip;\n D.status = 0;\n DumpHeader(D);\n DumpByte(f.upvalues.length, D);\n DumpFunction(f, null, D);\n return D.status;\n};\n\nmodule.exports.luaU_dump = luaU_dump;\n","/* global window, exports, define */\n\n!function() {\n 'use strict'\n\n var re = {\n not_string: /[^s]/,\n not_bool: /[^t]/,\n not_type: /[^T]/,\n not_primitive: /[^v]/,\n number: /[diefg]/,\n numeric_arg: /[bcdiefguxX]/,\n json: /[j]/,\n not_json: /[^j]/,\n text: /^[^\\x25]+/,\n modulo: /^\\x25{2}/,\n placeholder: /^\\x25(?:([1-9]\\d*)\\$|\\(([^\\)]+)\\))?(\\+)?(0|'[^$])?(-)?(\\d+)?(?:\\.(\\d+))?([b-gijostTuvxX])/,\n key: /^([a-z_][a-z_\\d]*)/i,\n key_access: /^\\.([a-z_][a-z_\\d]*)/i,\n index_access: /^\\[(\\d+)\\]/,\n sign: /^[\\+\\-]/\n }\n\n function sprintf(key) {\n // `arguments` is not an array, but should be fine for this call\n return sprintf_format(sprintf_parse(key), arguments)\n }\n\n function vsprintf(fmt, argv) {\n return sprintf.apply(null, [fmt].concat(argv || []))\n }\n\n function sprintf_format(parse_tree, argv) {\n var cursor = 1, tree_length = parse_tree.length, arg, output = '', i, k, match, pad, pad_character, pad_length, is_positive, sign\n for (i = 0; i < tree_length; i++) {\n if (typeof parse_tree[i] === 'string') {\n output += parse_tree[i]\n }\n else if (Array.isArray(parse_tree[i])) {\n match = parse_tree[i] // convenience purposes only\n if (match[2]) { // keyword argument\n arg = argv[cursor]\n for (k = 0; k < match[2].length; k++) {\n if (!arg.hasOwnProperty(match[2][k])) {\n throw new Error(sprintf('[sprintf] property \"%s\" does not exist', match[2][k]))\n }\n arg = arg[match[2][k]]\n }\n }\n else if (match[1]) { // positional argument (explicit)\n arg = argv[match[1]]\n }\n else { // positional argument (implicit)\n arg = argv[cursor++]\n }\n\n if (re.not_type.test(match[8]) && re.not_primitive.test(match[8]) && arg instanceof Function) {\n arg = arg()\n }\n\n if (re.numeric_arg.test(match[8]) && (typeof arg !== 'number' && isNaN(arg))) {\n throw new TypeError(sprintf('[sprintf] expecting number but found %T', arg))\n }\n\n if (re.number.test(match[8])) {\n is_positive = arg >= 0\n }\n\n switch (match[8]) {\n case 'b':\n arg = parseInt(arg, 10).toString(2)\n break\n case 'c':\n arg = String.fromCharCode(parseInt(arg, 10))\n break\n case 'd':\n case 'i':\n arg = parseInt(arg, 10)\n break\n case 'j':\n arg = JSON.stringify(arg, null, match[6] ? parseInt(match[6]) : 0)\n break\n case 'e':\n arg = match[7] ? parseFloat(arg).toExponential(match[7]) : parseFloat(arg).toExponential()\n break\n case 'f':\n arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg)\n break\n case 'g':\n arg = match[7] ? String(Number(arg.toPrecision(match[7]))) : parseFloat(arg)\n break\n case 'o':\n arg = (parseInt(arg, 10) >>> 0).toString(8)\n break\n case 's':\n arg = String(arg)\n arg = (match[7] ? arg.substring(0, match[7]) : arg)\n break\n case 't':\n arg = String(!!arg)\n arg = (match[7] ? arg.substring(0, match[7]) : arg)\n break\n case 'T':\n arg = Object.prototype.toString.call(arg).slice(8, -1).toLowerCase()\n arg = (match[7] ? arg.substring(0, match[7]) : arg)\n break\n case 'u':\n arg = parseInt(arg, 10) >>> 0\n break\n case 'v':\n arg = arg.valueOf()\n arg = (match[7] ? arg.substring(0, match[7]) : arg)\n break\n case 'x':\n arg = (parseInt(arg, 10) >>> 0).toString(16)\n break\n case 'X':\n arg = (parseInt(arg, 10) >>> 0).toString(16).toUpperCase()\n break\n }\n if (re.json.test(match[8])) {\n output += arg\n }\n else {\n if (re.number.test(match[8]) && (!is_positive || match[3])) {\n sign = is_positive ? '+' : '-'\n arg = arg.toString().replace(re.sign, '')\n }\n else {\n sign = ''\n }\n pad_character = match[4] ? match[4] === '0' ? '0' : match[4].charAt(1) : ' '\n pad_length = match[6] - (sign + arg).length\n pad = match[6] ? (pad_length > 0 ? pad_character.repeat(pad_length) : '') : ''\n output += match[5] ? sign + arg + pad : (pad_character === '0' ? sign + pad + arg : pad + sign + arg)\n }\n }\n }\n return output\n }\n\n var sprintf_cache = Object.create(null)\n\n function sprintf_parse(fmt) {\n if (sprintf_cache[fmt]) {\n return sprintf_cache[fmt]\n }\n\n var _fmt = fmt, match, parse_tree = [], arg_names = 0\n while (_fmt) {\n if ((match = re.text.exec(_fmt)) !== null) {\n parse_tree.push(match[0])\n }\n else if ((match = re.modulo.exec(_fmt)) !== null) {\n parse_tree.push('%')\n }\n else if ((match = re.placeholder.exec(_fmt)) !== null) {\n if (match[2]) {\n arg_names |= 1\n var field_list = [], replacement_field = match[2], field_match = []\n if ((field_match = re.key.exec(replacement_field)) !== null) {\n field_list.push(field_match[1])\n while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {\n if ((field_match = re.key_access.exec(replacement_field)) !== null) {\n field_list.push(field_match[1])\n }\n else if ((field_match = re.index_access.exec(replacement_field)) !== null) {\n field_list.push(field_match[1])\n }\n else {\n throw new SyntaxError('[sprintf] failed to parse named argument key')\n }\n }\n }\n else {\n throw new SyntaxError('[sprintf] failed to parse named argument key')\n }\n match[2] = field_list\n }\n else {\n arg_names |= 2\n }\n if (arg_names === 3) {\n throw new Error('[sprintf] mixing positional and named placeholders is not (yet) supported')\n }\n parse_tree.push(match)\n }\n else {\n throw new SyntaxError('[sprintf] unexpected placeholder')\n }\n _fmt = _fmt.substring(match[0].length)\n }\n return sprintf_cache[fmt] = parse_tree\n }\n\n /**\n * export to either browser or node.js\n */\n /* eslint-disable quote-props */\n if (typeof exports !== 'undefined') {\n exports['sprintf'] = sprintf\n exports['vsprintf'] = vsprintf\n }\n if (typeof window !== 'undefined') {\n window['sprintf'] = sprintf\n window['vsprintf'] = vsprintf\n\n if (typeof define === 'function' && define['amd']) {\n define(function() {\n return {\n 'sprintf': sprintf,\n 'vsprintf': vsprintf\n }\n })\n }\n }\n /* eslint-enable quote-props */\n}()\n","\"use strict\";\n\nconst { lua_pop } = require('./lua.js');\nconst { luaL_requiref } = require('./lauxlib.js');\nconst { to_luastring } = require(\"./fengaricore.js\");\n\nconst loadedlibs = {};\n\n/* export before requiring lualib.js */\nconst luaL_openlibs = function(L) {\n /* \"require\" functions from 'loadedlibs' and set results to global table */\n for (let lib in loadedlibs) {\n luaL_requiref(L, to_luastring(lib), loadedlibs[lib], 1);\n lua_pop(L, 1); /* remove lib */\n }\n};\nmodule.exports.luaL_openlibs = luaL_openlibs;\n\nconst lualib = require('./lualib.js');\nconst { luaopen_base } = require('./lbaselib.js');\nconst { luaopen_coroutine } = require('./lcorolib.js');\nconst { luaopen_debug } = require('./ldblib.js');\nconst { luaopen_math } = require('./lmathlib.js');\nconst { luaopen_package } = require('./loadlib.js');\nconst { luaopen_os } = require('./loslib.js');\nconst { luaopen_string } = require('./lstrlib.js');\nconst { luaopen_table } = require('./ltablib.js');\nconst { luaopen_utf8 } = require('./lutf8lib.js');\n\nloadedlibs[\"_G\"] = luaopen_base,\nloadedlibs[lualib.LUA_LOADLIBNAME] = luaopen_package;\nloadedlibs[lualib.LUA_COLIBNAME] = luaopen_coroutine;\nloadedlibs[lualib.LUA_TABLIBNAME] = luaopen_table;\nloadedlibs[lualib.LUA_OSLIBNAME] = luaopen_os;\nloadedlibs[lualib.LUA_STRLIBNAME] = luaopen_string;\nloadedlibs[lualib.LUA_MATHLIBNAME] = luaopen_math;\nloadedlibs[lualib.LUA_UTF8LIBNAME] = luaopen_utf8;\nloadedlibs[lualib.LUA_DBLIBNAME] = luaopen_debug;\nif (typeof process !== \"undefined\")\n loadedlibs[lualib.LUA_IOLIBNAME] = require('./liolib.js').luaopen_io;\n\n/* Extension: fengari library */\nconst { luaopen_fengari } = require('./fengarilib.js');\nloadedlibs[lualib.LUA_FENGARILIBNAME] = luaopen_fengari;\n"],"sourceRoot":""} \ No newline at end of file diff --git a/root/static/hidden: text$lua -> bool.lua b/root/static/hidden: text$lua -> bool.lua new file mode 100644 index 0000000..b30e187 --- /dev/null +++ b/root/static/hidden: text$lua -> bool.lua @@ -0,0 +1 @@ +return true diff --git a/root/static/highlight-pack/application$javascript.js b/root/static/highlight-pack/application$javascript.js new file mode 100644 index 0000000..0a64756 --- /dev/null +++ b/root/static/highlight-pack/application$javascript.js @@ -0,0 +1,2 @@ +/*! highlight.js v9.13.1 | BSD3 License | git.io/hljslicense */ +!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/g,"&").replace(//g,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=M.exec(o))return w(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||w(i))return i}function o(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function c(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function u(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function c(e){l+=""}function u(e){("start"===e.event?o:c)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substring(s,g[0].offset)),s=g[0].offset,g===e){f.reverse().forEach(c);do u(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===s);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),u(g.splice(0,1)[0])}return l+n(a.substr(s))}function s(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(n){return o(e,{v:null},n)})),e.cached_variants||e.eW&&[o(e)]||[e]}function l(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):B(a.k).forEach(function(e){c(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.endSameAsBegin&&(a.e=a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]),a.c=Array.prototype.concat.apply([],a.c.map(function(e){return s("self"===e?a:e)})),a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var u=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=u.length?t(u.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e){return new RegExp(e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")}function c(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t].endSameAsBegin&&(n.c[t].eR=o(n.c[t].bR.exec(e)[0])),n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function s(e,n){return!a&&r(n.iR,e)}function p(e,n){var t=R.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function d(e,n,t,r){var a=r?"":j.classPrefix,i='',i+n+o}function h(){var e,t,r,a;if(!E.k)return n(k);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(k);r;)a+=n(k.substring(t,r.index)),e=p(E,r),e?(M+=e[1],a+=d(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(k);return a+n(k.substr(t))}function b(){var e="string"==typeof E.sL;if(e&&!L[E.sL])return n(k);var t=e?f(E.sL,k,!0,B[E.sL]):g(k,E.sL.length?E.sL:void 0);return E.r>0&&(M+=t.r),e&&(B[E.sL]=t.top),d(t.language,t.value,!1,!0)}function v(){y+=null!=E.sL?b():h(),k=""}function m(e){y+=e.cN?d(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function N(e,n){if(k+=e,null==n)return v(),0;var t=c(n,E);if(t)return t.skip?k+=n:(t.eB&&(k+=n),v(),t.rB||t.eB||(k=n)),m(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?k+=n:(a.rE||a.eE||(k+=n),v(),a.eE&&(k=n));do E.cN&&(y+=I),E.skip||E.sL||(M+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&(r.endSameAsBegin&&(r.starts.eR=r.eR),m(r.starts,"")),a.rE?0:n.length}if(s(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return k+=n,n.length||1}var R=w(e);if(!R)throw new Error('Unknown language: "'+e+'"');l(R);var x,E=i||R,B={},y="";for(x=E;x!==R;x=x.parent)x.cN&&(y=d(x.cN,"",!0)+y);var k="",M=0;try{for(var C,A,S=0;;){if(E.t.lastIndex=S,C=E.t.exec(t),!C)break;A=N(t.substring(S,C.index),C[0]),S=C.index+A}for(N(t.substr(S)),x=E;x.parent;x=x.parent)x.cN&&(y+=I);return{r:M,value:y,language:e,top:E}}catch(O){if(O.message&&-1!==O.message.indexOf("Illegal"))return{r:0,value:n(t)};throw O}}function g(e,t){t=t||j.languages||B(L);var r={r:0,value:n(e)},a=r;return t.filter(w).filter(x).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function p(e){return j.tabReplace||j.useBR?e.replace(C,function(e,n){return j.useBR&&"\n"===e?"
":j.tabReplace?n.replace(/\t/g,j.tabReplace):""}):e}function d(e,n,t){var r=n?y[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function h(e){var n,t,r,o,s,l=i(e);a(l)||(j.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):n=e,s=n.textContent,r=l?f(l,s,!0):g(s),t=c(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=u(t,c(o),s)),r.value=p(r.value),e.innerHTML=r.value,e.className=d(e.className,l,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function b(e){j=o(j,e)}function v(){if(!v.called){v.called=!0;var e=document.querySelectorAll("pre code");E.forEach.call(e,h)}}function m(){addEventListener("DOMContentLoaded",v,!1),addEventListener("load",v,!1)}function N(n,t){var r=L[n]=t(e);r.aliases&&r.aliases.forEach(function(e){y[e]=n})}function R(){return B(L)}function w(e){return e=(e||"").toLowerCase(),L[e]||L[y[e]]}function x(e){var n=w(e);return n&&!n.disableAutodetect}var E=[],B=Object.keys,L={},y={},k=/^(no-?highlight|plain|text)$/i,M=/\blang(?:uage)?-([\w-]+)\b/i,C=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,I="
",j={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=f,e.highlightAuto=g,e.fixMarkup=p,e.highlightBlock=h,e.configure=b,e.initHighlighting=v,e.initHighlightingOnLoad=m,e.registerLanguage=N,e.listLanguages=R,e.getLanguage=w,e.autoDetection=x,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("moonscript",function(e){var t={keyword:"if then not for in while do return else elseif break continue switch and or unless when class extends super local import export from using",literal:"true false nil",built_in:"_G _VERSION assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall coroutine debug io math os package string table"},r="[A-Za-z$_][0-9A-Za-z$_]*",s={cN:"subst",b:/#\{/,e:/}/,k:t},a=[e.inherit(e.CNM,{starts:{e:"(\\s*/)?",r:0}}),{cN:"string",v:[{b:/'/,e:/'/,c:[e.BE]},{b:/"/,e:/"/,c:[e.BE,s]}]},{cN:"built_in",b:"@__"+e.IR},{b:"@"+e.IR},{b:e.IR+"\\\\"+e.IR}];s.c=a;var c=e.inherit(e.TM,{b:r}),n="(\\(.*\\))?\\s*\\B[-=]>",i={cN:"params",b:"\\([^\\(]",rB:!0,c:[{b:/\(/,e:/\)/,k:t,c:["self"].concat(a)}]};return{aliases:["moon"],k:t,i:/\/\*/,c:a.concat([e.C("--","$"),{cN:"function",b:"^\\s*"+r+"\\s*=\\s*"+n,e:"[-=]>",rB:!0,c:[c,i]},{b:/[\(,:=]\s*/,r:0,c:[{cN:"function",b:n,e:"[-=]>",rB:!0,c:[i]}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:!0,i:/[:="\[\]]/,c:[c]},c]},{cN:"name",b:r+":",e:":",rB:!0,rE:!0,r:0}])}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/\b-?[a-z\._]+\b/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage("lua",function(e){var t="\\[=*\\[",a="\\]=*\\]",r={b:t,e:a,c:["self"]},n=[e.C("--(?!"+t+")","$"),e.C("--"+t,a,{c:[r],r:10})];return{l:e.UIR,k:{literal:"true false nil",keyword:"and break do else elseif end for goto if in local not or repeat return then until while",built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstringmodule next pairs pcall print rawequal rawget rawset require select setfenvsetmetatable tonumber tostring type unpack xpcall arg selfcoroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"},c:n.concat([{cN:"function",bK:"function",e:"\\)",c:[e.inherit(e.TM,{b:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{cN:"params",b:"\\(",eW:!0,c:n}].concat(n)},e.CNM,e.ASM,e.QSM,{cN:"string",b:t,e:a,c:[r],r:5}])}});hljs.registerLanguage("xml",function(s){var e="[A-Za-z0-9\\._:-]+",t={eW:!0,i:/`]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist"],cI:!0,c:[{cN:"meta",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},s.C("",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"meta",b:/<\?xml/,e:/\?>/,r:10},{b:/<\?(php)?/,e:/\?>/,sL:"php",c:[{b:"/\\*",e:"\\*/",skip:!0},{b:'b"',e:'"',skip:!0},{b:"b'",e:"'",skip:!0},s.inherit(s.ASM,{i:null,cN:null,c:null,skip:!0}),s.inherit(s.QSM,{i:null,cN:null,c:null,skip:!0})]},{cN:"tag",b:"|$)",e:">",k:{name:"style"},c:[t],starts:{e:"",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"|$)",e:">",k:{name:"script"},c:[t],starts:{e:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"tag",b:"",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",t={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/},{b:/\(/,e:/\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",i:/:/,c:[{cN:"keyword",b:/\w+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:c,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,t]}]}});hljs.registerLanguage("javascript",function(e){var r="[A-Za-z$_][0-9A-Za-z$_]*",t={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},a={cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},n={cN:"subst",b:"\\$\\{",e:"\\}",k:t,c:[]},c={cN:"string",b:"`",e:"`",c:[e.BE,n]};n.c=[e.ASM,e.QSM,c,a,e.RM];var s=n.c.concat([e.CBCM,e.CLCM]);return{aliases:["js","jsx"],k:t,c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,c,e.CLCM,e.CBCM,a,{b:/[{,]\s*/,r:0,c:[{b:r+"\\s*:",rB:!0,r:0,c:[{cN:"attr",b:r,r:0}]}]},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+r+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:r},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:s}]}]},{b://,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:[{b:/<\w+\s*\/>/,skip:!0},"self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:r}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:s}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}});hljs.registerLanguage("markdown",function(e){return{aliases:["md","mkdown","mkd"],c:[{cN:"section",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"quote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"^```w*s*$",e:"^```s*$"},{b:"`.+?`"},{b:"^( {4}| )",e:"$",r:0}]},{b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].*?[\\)\\]]",rB:!0,c:[{cN:"string",b:"\\[",e:"\\]",eB:!0,rE:!0,r:0},{cN:"link",b:"\\]\\(",e:"\\)",eB:!0,eE:!0},{cN:"symbol",b:"\\]\\[",e:"\\]",eB:!0,eE:!0}],r:10},{b:/^\[[^\n]+\]:/,rB:!0,c:[{cN:"symbol",b:/\[/,e:/\]/,eB:!0,eE:!0},{cN:"link",b:/:\s*/,e:/$/,eB:!0}]}]}}); \ No newline at end of file diff --git a/static/highlight.pack.js b/static/highlight.pack.js deleted file mode 100644 index 0a64756..0000000 --- a/static/highlight.pack.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! highlight.js v9.13.1 | BSD3 License | git.io/hljslicense */ -!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/g,"&").replace(//g,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=M.exec(o))return w(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||w(i))return i}function o(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function c(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function u(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function c(e){l+=""}function u(e){("start"===e.event?o:c)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substring(s,g[0].offset)),s=g[0].offset,g===e){f.reverse().forEach(c);do u(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===s);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),u(g.splice(0,1)[0])}return l+n(a.substr(s))}function s(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(n){return o(e,{v:null},n)})),e.cached_variants||e.eW&&[o(e)]||[e]}function l(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):B(a.k).forEach(function(e){c(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.endSameAsBegin&&(a.e=a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]),a.c=Array.prototype.concat.apply([],a.c.map(function(e){return s("self"===e?a:e)})),a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var u=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=u.length?t(u.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e){return new RegExp(e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")}function c(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t].endSameAsBegin&&(n.c[t].eR=o(n.c[t].bR.exec(e)[0])),n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function s(e,n){return!a&&r(n.iR,e)}function p(e,n){var t=R.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function d(e,n,t,r){var a=r?"":j.classPrefix,i='',i+n+o}function h(){var e,t,r,a;if(!E.k)return n(k);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(k);r;)a+=n(k.substring(t,r.index)),e=p(E,r),e?(M+=e[1],a+=d(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(k);return a+n(k.substr(t))}function b(){var e="string"==typeof E.sL;if(e&&!L[E.sL])return n(k);var t=e?f(E.sL,k,!0,B[E.sL]):g(k,E.sL.length?E.sL:void 0);return E.r>0&&(M+=t.r),e&&(B[E.sL]=t.top),d(t.language,t.value,!1,!0)}function v(){y+=null!=E.sL?b():h(),k=""}function m(e){y+=e.cN?d(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function N(e,n){if(k+=e,null==n)return v(),0;var t=c(n,E);if(t)return t.skip?k+=n:(t.eB&&(k+=n),v(),t.rB||t.eB||(k=n)),m(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?k+=n:(a.rE||a.eE||(k+=n),v(),a.eE&&(k=n));do E.cN&&(y+=I),E.skip||E.sL||(M+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&(r.endSameAsBegin&&(r.starts.eR=r.eR),m(r.starts,"")),a.rE?0:n.length}if(s(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return k+=n,n.length||1}var R=w(e);if(!R)throw new Error('Unknown language: "'+e+'"');l(R);var x,E=i||R,B={},y="";for(x=E;x!==R;x=x.parent)x.cN&&(y=d(x.cN,"",!0)+y);var k="",M=0;try{for(var C,A,S=0;;){if(E.t.lastIndex=S,C=E.t.exec(t),!C)break;A=N(t.substring(S,C.index),C[0]),S=C.index+A}for(N(t.substr(S)),x=E;x.parent;x=x.parent)x.cN&&(y+=I);return{r:M,value:y,language:e,top:E}}catch(O){if(O.message&&-1!==O.message.indexOf("Illegal"))return{r:0,value:n(t)};throw O}}function g(e,t){t=t||j.languages||B(L);var r={r:0,value:n(e)},a=r;return t.filter(w).filter(x).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function p(e){return j.tabReplace||j.useBR?e.replace(C,function(e,n){return j.useBR&&"\n"===e?"
":j.tabReplace?n.replace(/\t/g,j.tabReplace):""}):e}function d(e,n,t){var r=n?y[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function h(e){var n,t,r,o,s,l=i(e);a(l)||(j.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):n=e,s=n.textContent,r=l?f(l,s,!0):g(s),t=c(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=u(t,c(o),s)),r.value=p(r.value),e.innerHTML=r.value,e.className=d(e.className,l,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function b(e){j=o(j,e)}function v(){if(!v.called){v.called=!0;var e=document.querySelectorAll("pre code");E.forEach.call(e,h)}}function m(){addEventListener("DOMContentLoaded",v,!1),addEventListener("load",v,!1)}function N(n,t){var r=L[n]=t(e);r.aliases&&r.aliases.forEach(function(e){y[e]=n})}function R(){return B(L)}function w(e){return e=(e||"").toLowerCase(),L[e]||L[y[e]]}function x(e){var n=w(e);return n&&!n.disableAutodetect}var E=[],B=Object.keys,L={},y={},k=/^(no-?highlight|plain|text)$/i,M=/\blang(?:uage)?-([\w-]+)\b/i,C=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,I="
",j={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=f,e.highlightAuto=g,e.fixMarkup=p,e.highlightBlock=h,e.configure=b,e.initHighlighting=v,e.initHighlightingOnLoad=m,e.registerLanguage=N,e.listLanguages=R,e.getLanguage=w,e.autoDetection=x,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("moonscript",function(e){var t={keyword:"if then not for in while do return else elseif break continue switch and or unless when class extends super local import export from using",literal:"true false nil",built_in:"_G _VERSION assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall coroutine debug io math os package string table"},r="[A-Za-z$_][0-9A-Za-z$_]*",s={cN:"subst",b:/#\{/,e:/}/,k:t},a=[e.inherit(e.CNM,{starts:{e:"(\\s*/)?",r:0}}),{cN:"string",v:[{b:/'/,e:/'/,c:[e.BE]},{b:/"/,e:/"/,c:[e.BE,s]}]},{cN:"built_in",b:"@__"+e.IR},{b:"@"+e.IR},{b:e.IR+"\\\\"+e.IR}];s.c=a;var c=e.inherit(e.TM,{b:r}),n="(\\(.*\\))?\\s*\\B[-=]>",i={cN:"params",b:"\\([^\\(]",rB:!0,c:[{b:/\(/,e:/\)/,k:t,c:["self"].concat(a)}]};return{aliases:["moon"],k:t,i:/\/\*/,c:a.concat([e.C("--","$"),{cN:"function",b:"^\\s*"+r+"\\s*=\\s*"+n,e:"[-=]>",rB:!0,c:[c,i]},{b:/[\(,:=]\s*/,r:0,c:[{cN:"function",b:n,e:"[-=]>",rB:!0,c:[i]}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:!0,i:/[:="\[\]]/,c:[c]},c]},{cN:"name",b:r+":",e:":",rB:!0,rE:!0,r:0}])}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/\b-?[a-z\._]+\b/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage("lua",function(e){var t="\\[=*\\[",a="\\]=*\\]",r={b:t,e:a,c:["self"]},n=[e.C("--(?!"+t+")","$"),e.C("--"+t,a,{c:[r],r:10})];return{l:e.UIR,k:{literal:"true false nil",keyword:"and break do else elseif end for goto if in local not or repeat return then until while",built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstringmodule next pairs pcall print rawequal rawget rawset require select setfenvsetmetatable tonumber tostring type unpack xpcall arg selfcoroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"},c:n.concat([{cN:"function",bK:"function",e:"\\)",c:[e.inherit(e.TM,{b:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{cN:"params",b:"\\(",eW:!0,c:n}].concat(n)},e.CNM,e.ASM,e.QSM,{cN:"string",b:t,e:a,c:[r],r:5}])}});hljs.registerLanguage("xml",function(s){var e="[A-Za-z0-9\\._:-]+",t={eW:!0,i:/`]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist"],cI:!0,c:[{cN:"meta",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},s.C("",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"meta",b:/<\?xml/,e:/\?>/,r:10},{b:/<\?(php)?/,e:/\?>/,sL:"php",c:[{b:"/\\*",e:"\\*/",skip:!0},{b:'b"',e:'"',skip:!0},{b:"b'",e:"'",skip:!0},s.inherit(s.ASM,{i:null,cN:null,c:null,skip:!0}),s.inherit(s.QSM,{i:null,cN:null,c:null,skip:!0})]},{cN:"tag",b:"|$)",e:">",k:{name:"style"},c:[t],starts:{e:"",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"|$)",e:">",k:{name:"script"},c:[t],starts:{e:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"tag",b:"",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",t={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/},{b:/\(/,e:/\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",i:/:/,c:[{cN:"keyword",b:/\w+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:c,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,t]}]}});hljs.registerLanguage("javascript",function(e){var r="[A-Za-z$_][0-9A-Za-z$_]*",t={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},a={cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},n={cN:"subst",b:"\\$\\{",e:"\\}",k:t,c:[]},c={cN:"string",b:"`",e:"`",c:[e.BE,n]};n.c=[e.ASM,e.QSM,c,a,e.RM];var s=n.c.concat([e.CBCM,e.CLCM]);return{aliases:["js","jsx"],k:t,c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,c,e.CLCM,e.CBCM,a,{b:/[{,]\s*/,r:0,c:[{b:r+"\\s*:",rB:!0,r:0,c:[{cN:"attr",b:r,r:0}]}]},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+r+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:r},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:s}]}]},{b://,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:[{b:/<\w+\s*\/>/,skip:!0},"self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:r}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:s}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}});hljs.registerLanguage("markdown",function(e){return{aliases:["md","mkdown","mkd"],c:[{cN:"section",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"quote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"^```w*s*$",e:"^```s*$"},{b:"`.+?`"},{b:"^( {4}| )",e:"$",r:0}]},{b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].*?[\\)\\]]",rB:!0,c:[{cN:"string",b:"\\[",e:"\\]",eB:!0,rE:!0,r:0},{cN:"link",b:"\\]\\(",e:"\\)",eB:!0,eE:!0},{cN:"symbol",b:"\\]\\[",e:"\\]",eB:!0,eE:!0}],r:10},{b:/^\[[^\n]+\]:/,rB:!0,c:[{cN:"symbol",b:/\[/,e:/\]/,eB:!0,eE:!0},{cN:"link",b:/:\s*/,e:/$/,eB:!0}]}]}}); \ No newline at end of file diff --git a/tup.config b/tup.config index 54e707c..5d71cbd 100644 --- a/tup.config +++ b/tup.config @@ -1,2 +1,2 @@ CONFIG_FENGARI_VERSION=v0.1.4 -CONFIG_SASS_ARGS=-mauto +CONFIG_SASS_ARGS= -- cgit v1.2.3 From 7b61518128ac3c666406f76756994a70adede4f2 Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 10 Oct 2019 20:58:16 +0200 Subject: fix mmm-embed --- mmm/mmmfs/converts.moon | 4 +++- .../_base: text$moonscript -> table.moon | 26 ++++++++++++++++++++-- ...it: text$moonscript -> fn -> mmm$component.moon | 2 -- ...te: text$moonscript -> fn -> mmm$component.moon | 2 -- ...ar: text$moonscript -> fn -> mmm$component.moon | 2 -- ...ar: text$moonscript -> fn -> mmm$component.moon | 2 -- ...tk: text$moonscript -> fn -> mmm$component.moon | 2 -- 7 files changed, 27 insertions(+), 13 deletions(-) diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon index 8d6b953..c3f0522 100644 --- a/mmm/mmmfs/converts.moon +++ b/mmm/mmmfs/converts.moon @@ -40,7 +40,9 @@ converts = { transform: (node) => if MODE == 'SERVER' then node else node.outerHTML }, { - inp: 'text/html%+frag', + -- inp: 'text/html%+frag', + -- @TODO: this doesn't feel right... maybe mmm/dom has to go? + inp: 'mmm/dom', out: 'text/html', transform: (html, fileder) => render html, fileder }, diff --git a/root/blog/aspect_ratios/interactive/_base: text$moonscript -> table.moon b/root/blog/aspect_ratios/interactive/_base: text$moonscript -> table.moon index d348f4b..f47e03f 100644 --- a/root/blog/aspect_ratios/interactive/_base: text$moonscript -> table.moon +++ b/root/blog/aspect_ratios/interactive/_base: text$moonscript -> table.moon @@ -1,7 +1,29 @@ -assert MODE == 'CLIENT', '[nossr]' +import div from require 'mmm.dom' + +if MODE ~= 'CLIENT' + class Dummy + render: => + div 'Interactive Example not available with Server-Side rendering', style: + position: 'relative' + resize: 'horizontal' + overflow: 'hidden' + + width: '576px' + height: '324px' + 'min-width': '324px' + 'max-width': '742px' + + margin: 'auto' + padding: '10px' + boxSizing: 'border-box' + background: 'var(--gray-bright)' + + return { + UIDemo: Dummy + Example: Dummy + } import CanvasApp from require 'mmm.canvasapp' -import div from require 'mmm.dom' class UIDemo extends CanvasApp width: nil diff --git a/root/blog/aspect_ratios/interactive/fit: text$moonscript -> fn -> mmm$component.moon b/root/blog/aspect_ratios/interactive/fit: text$moonscript -> fn -> mmm$component.moon index 499f9aa..33478bf 100644 --- a/root/blog/aspect_ratios/interactive/fit: text$moonscript -> fn -> mmm$component.moon +++ b/root/blog/aspect_ratios/interactive/fit: text$moonscript -> fn -> mmm$component.moon @@ -1,6 +1,4 @@ => - assert MODE == 'CLIENT', '[nossr]' - import UIDemo from @get '_base: table' class FitDemo extends UIDemo diff --git a/root/blog/aspect_ratios/interactive/perforate: text$moonscript -> fn -> mmm$component.moon b/root/blog/aspect_ratios/interactive/perforate: text$moonscript -> fn -> mmm$component.moon index 38aeac1..905c313 100644 --- a/root/blog/aspect_ratios/interactive/perforate: text$moonscript -> fn -> mmm$component.moon +++ b/root/blog/aspect_ratios/interactive/perforate: text$moonscript -> fn -> mmm$component.moon @@ -1,6 +1,4 @@ => - assert MODE == 'CLIENT', '[nossr]' - import UIDemo from @get '_base: table' arr = (args) -> diff --git a/root/blog/aspect_ratios/interactive/sidebar: text$moonscript -> fn -> mmm$component.moon b/root/blog/aspect_ratios/interactive/sidebar: text$moonscript -> fn -> mmm$component.moon index 2017e20..56e6cea 100644 --- a/root/blog/aspect_ratios/interactive/sidebar: text$moonscript -> fn -> mmm$component.moon +++ b/root/blog/aspect_ratios/interactive/sidebar: text$moonscript -> fn -> mmm$component.moon @@ -1,6 +1,4 @@ => - assert MODE == 'CLIENT', '[nossr]' - import Box, Example from @get '_base: table' class Sidebar extends Example diff --git a/root/blog/aspect_ratios/interactive/tear: text$moonscript -> fn -> mmm$component.moon b/root/blog/aspect_ratios/interactive/tear: text$moonscript -> fn -> mmm$component.moon index f108e0f..1705b80 100644 --- a/root/blog/aspect_ratios/interactive/tear: text$moonscript -> fn -> mmm$component.moon +++ b/root/blog/aspect_ratios/interactive/tear: text$moonscript -> fn -> mmm$component.moon @@ -1,6 +1,4 @@ => - assert MODE == 'CLIENT', '[nossr]' - import UIDemo from @get '_base: table' arr = (args) -> diff --git a/root/blog/aspect_ratios/interactive/vtk: text$moonscript -> fn -> mmm$component.moon b/root/blog/aspect_ratios/interactive/vtk: text$moonscript -> fn -> mmm$component.moon index dae4dfb..c2d17d0 100644 --- a/root/blog/aspect_ratios/interactive/vtk: text$moonscript -> fn -> mmm$component.moon +++ b/root/blog/aspect_ratios/interactive/vtk: text$moonscript -> fn -> mmm$component.moon @@ -1,6 +1,4 @@ => - assert MODE == 'CLIENT', '[nossr]' - import Box, Example from @get '_base: table' class VTK extends Example -- cgit v1.2.3 From ffa343c41fca7a38dc00bb929d31fb7552578900 Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 10 Oct 2019 21:01:37 +0200 Subject: serve from root/ in docker --- Dockerfile | 2 +- build/import.moon | 2 +- tup.docker.config | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 273043a..ef1246b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,4 +16,4 @@ WORKDIR /code RUN tup init && tup generate --config tup.docker.config build-static.sh && ./build-static.sh EXPOSE 8000 -ENTRYPOINT ["moon", "build/server.moon", "sql:/db.sqlite3", "0.0.0.0", "8000"] +ENTRYPOINT ["moon", "build/server.moon", "fs", "0.0.0.0", "8000"] diff --git a/build/import.moon b/build/import.moon index 1e4df31..ba99b03 100644 --- a/build/import.moon +++ b/build/import.moon @@ -10,7 +10,7 @@ add '?/init.server' require 'mmm' require 'lfs' import Fileder, Key from require 'mmm.mmmfs.fileder' -import SQLStore from require 'mmm.mmmfs.drivers.sql' +import SQLStore from require 'mmm.mmmfs.stores.sql' -- usage: -- moon import.moon [output.sqlite3] diff --git a/tup.docker.config b/tup.docker.config index 7299d26..5d71cbd 100644 --- a/tup.docker.config +++ b/tup.docker.config @@ -1,2 +1,2 @@ CONFIG_FENGARI_VERSION=v0.1.4 -CONFIG_SASS_ARGS=-m +CONFIG_SASS_ARGS= -- cgit v1.2.3 From b36a1a6c61a6e8bff156ce4e2dc66fe8ed8cd95e Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 10 Oct 2019 22:56:26 +0200 Subject: ?index and ?tree as real facets with typecasting to application/json --- build/server.moon | 71 ++++++++++++++++++++--------------------------- mmm/mmmfs/conversion.moon | 18 ++++++++++++ mmm/mmmfs/converts.moon | 24 ++++++++++++++++ mmm/mmmfs/fileder.moon | 10 +++++++ 4 files changed, 82 insertions(+), 41 deletions(-) diff --git a/build/server.moon b/build/server.moon index ca08874..df18472 100644 --- a/build/server.moon +++ b/build/server.moon @@ -10,6 +10,7 @@ add '?/init.server' require 'mmm' import Key, dir_base, load_tree from require 'mmm.mmmfs.fileder' +import convert from require 'mmm.mmmfs.conversion' import get_store from require 'mmm.mmmfs.stores' import decodeURI from require 'http.util' @@ -17,22 +18,6 @@ lfs = require 'lfs' server = require 'http.server' headers = require 'http.headers' -tojson = (obj) -> - switch type obj - when 'string' - string.format '%q', obj - when 'table' - if obj[1] or not next obj - "[#{table.concat [tojson c for c in *obj], ','}]" - else - "{#{table.concat ["#{tojson k}: #{tojson v}" for k,v in pairs obj], ', '}}" - when 'number' - tostring obj - when 'boolean' - tostring obj - when nil - 'null' - class Server new: (@store, opts={}) => opts = {k,v for k,v in pairs opts} @@ -52,27 +37,31 @@ class Server handle: (method, path, facet) => fileder = load_tree @store, path -- @tree\walk path + + if not fileder + -- fileder not found + 404, "fileder '#{path}' not found" + switch method when 'GET', 'HEAD' - if fileder and facet - -- fileder and facet given - if not fileder\has_facet facet.name - return 404, "facet '#{facet.name}' not found in fileder '#{path}'" - - val = fileder\get facet - if val - 200, val + val = switch facet.name + when '?index', '?tree' + -- serve fileder index + -- '?index': one level deep + -- '?tree': recursively + index = fileder\get_index facet.name == '?tree' + convert 'table', facet.type, index else - 406, "cant convert facet '#{facet.name}' to '#{facet.type}'" - elseif fileder - -- no facet given - facets = [{k.name, k.type} for k,v in pairs fileder.facets] - children = [f.path for f in *fileder.children] - contents = tojson :facets, :children - 200, contents + -- fileder and facet given + if not fileder\has_facet facet.name + return 404, "facet '#{facet.name}' not found in fileder '#{path}'" + + fileder\get facet + + if val + 200, val else - -- fileder not found - 404, "fileder '#{path}' not found" + 406, "cant convert facet '#{facet.name}' to '#{facet.type}'" else 501, "not implemented" @@ -86,14 +75,15 @@ class Server path_facet or= path path, facet = path_facet\match '(.*)/([^/]*)' - if facet ~= '?index' - type or= 'text/html' - type = type\match '%s*(.*)' - facet = Key facet, type - else - facet = nil + type or= 'text/html' + type = type\match '%s*(.*)' + facet = Key facet, type - status, body = @handle method, path, facet + ok, status, body = pcall @.handle, @, method, path, facet + if not ok + warn status, body + body = "Internal Server Error: #{status}" + status = 500 res = headers.new! response_type = if status > 299 then 'text/plain' @@ -109,7 +99,6 @@ class Server error: (sv, ctx, op, err, errno) => msg = "#{op} on #{tostring ctx} failed" msg = "#{msg}: #{err}" if err - print msg -- usage: -- moon server.moon [STORE] [host] [port] diff --git a/mmm/mmmfs/conversion.moon b/mmm/mmmfs/conversion.moon index 2c68dcc..31cbf5e 100644 --- a/mmm/mmmfs/conversion.moon +++ b/mmm/mmmfs/conversion.moon @@ -55,8 +55,26 @@ apply_conversions = (conversions, value, ...) -> value +-- find and apply a conversion path from 'have' to 'want' +-- * have - start type string or list of type strings +-- * want - stop type pattern +-- * value - value or map from have-types to values +-- returns converted value +convert = (have, want, value, ...) -> + conversions, start = get_conversions want, have + + if not conversions + warn "couldn't convert from '#{have}' to '#{want}'" + return + + if 'string' ~= type have + value = value[start] + + apply_conversions conversions, value, ... + { :converts :get_conversions :apply_conversions + :convert } diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon index c3f0522..823033e 100644 --- a/mmm/mmmfs/converts.moon +++ b/mmm/mmmfs/converts.moon @@ -211,6 +211,30 @@ converts = { out: 'URL -> %1', transform: (_, fileder, key) => "#{fileder.path}/#{key.name}:#{@from}" }, + { + inp: 'table', + out: 'application/json', + transform: do + tojson = (obj) -> + switch type obj + when 'string' + string.format '%q', obj + when 'table' + if obj[1] or not next obj + "[#{table.concat [tojson c for c in *obj], ','}]" + else + "{#{table.concat ["#{tojson k}: #{tojson v}" for k,v in pairs obj], ', '}}" + when 'number' + tostring obj + when 'boolean' + tostring obj + when 'nil' + 'null' + else + error "unknown type '#{type obj}'" + + (val) => tojson val + } } if MODE == 'SERVER' diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index 3e5c49f..a0e4f2b 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -122,6 +122,16 @@ class Fileder [name for name in pairs names] + get_index: (recursive=false) => + { + path: @path + facets: [{k.name, k.type} for k,v in pairs @facets] + children: if recursive + [child\get_index true for child in *@children] + else + [{ :path } for { :path } in *@children] + } + -- check whether a facet is directly available -- when passing a Key, set type to false to check for name only has: (...) => -- cgit v1.2.3 From 061372658a470534d6de51ee8c6e2c5154225736 Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 10 Oct 2019 17:12:18 +0200 Subject: add entr instructions --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 94a7f66..1319914 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,12 @@ You will need: - [discount](https://luarocks.org/modules/craigb/discount): `luarocks install discount` (requires libmarkdown2) - [busted](https://olivinelabs.com/busted/): `luarocks install busted` (for testing only) +### Live Reloading (during development) +[entr][entr] is useful for reloading the dev server when code outside the root changes: + + $ ls build/**.moon mmm/**.moon | entr -r moon build/server.moon fs + [moonscript]: https://moonscript.org/ [mmm]: https://mmm.s-ol.nu/ [tup]: https://gittup.org/tup +[entr]: http://eradman.com/entrproject/ -- cgit v1.2.3 From 9ab2f0fe3a1a043300536a057bafe5058d987d7f Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 10 Oct 2019 17:38:52 +0200 Subject: add $interactive facet with Browser --- build/server.moon | 20 ++++++++++++++++++++ mmm/mmmfs/browser.moon | 4 +++- mmm/mmmfs/layout.moon | 11 ----------- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/build/server.moon b/build/server.moon index df18472..693f00c 100644 --- a/build/server.moon +++ b/build/server.moon @@ -12,6 +12,8 @@ require 'mmm' import Key, dir_base, load_tree from require 'mmm.mmmfs.fileder' import convert from require 'mmm.mmmfs.conversion' import get_store from require 'mmm.mmmfs.stores' +import render from require 'mmm.mmmfs.layout' +import Browser from require 'mmm.mmmfs.browser' import decodeURI from require 'http.util' lfs = require 'lfs' @@ -45,6 +47,24 @@ class Server switch method when 'GET', 'HEAD' val = switch facet.name + when '?interactive' + export BROWSER + + root = load_tree @store + BROWSER = Browser root, path + render BROWSER\todom!, fileder, noview: true, scripts: " + " + when '?index', '?tree' -- serve fileder index -- '?index': one level deep diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index 37a386c..6321457 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -1,7 +1,7 @@ require = relative ..., 1 import Key from require '.fileder' import converts, get_conversions, apply_conversions from require '.conversion' -import ReactiveVar, get_or_create, text, elements from require 'mmm.component' +import ReactiveVar, get_or_create, text, elements, tohtml from require 'mmm.component' import pre, div, nav, span, button, a, code, select, option from elements import languages from require 'mmm.highlighting' @@ -240,6 +240,8 @@ class Browser navigate: (new) => @path\set new + todom: => tohtml @ + { :Browser } diff --git a/mmm/mmmfs/layout.moon b/mmm/mmmfs/layout.moon index 6c6a943..61519ae 100644 --- a/mmm/mmmfs/layout.moon +++ b/mmm/mmmfs/layout.moon @@ -153,17 +153,6 @@ render = (content, fileder, opts={}) -> ]] buf ..= opts.scripts - -- buf ..= " -- cgit v1.2.3 From 9632233c16a26f017c648faf36a6b26833e62f2e Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 10 Oct 2019 18:42:07 +0200 Subject: make fileders load just-in-time --- .ignore | 1 + build/import.moon | 2 +- build/render_all.moon | 4 +- build/server.moon | 6 +- mmm/mmmfs/browser.moon | 2 +- mmm/mmmfs/fileder.moon | 201 +- .../text$moonscript -> mmm$component.moon | 542 ++++ .../realities/text$moonscript -> mmm$dom.moon | 542 ---- .../text$moonscript -> fn -> mmm$dom.moon | 4 - root/static/mmm/application$lua.lua | 2701 ++++++++++++++++++++ root/static/style/text$css.css | 411 +++ 11 files changed, 3797 insertions(+), 619 deletions(-) create mode 100644 root/articles/realities/text$moonscript -> mmm$component.moon delete mode 100644 root/articles/realities/text$moonscript -> mmm$dom.moon create mode 100644 root/static/mmm/application$lua.lua create mode 100644 root/static/style/text$css.css diff --git a/.ignore b/.ignore index 4356adf..2df43f6 100644 --- a/.ignore +++ b/.ignore @@ -3,3 +3,4 @@ index.html $bundle.lua *.js *.js.map +*.lua diff --git a/build/import.moon b/build/import.moon index ba99b03..92d4397 100644 --- a/build/import.moon +++ b/build/import.moon @@ -9,7 +9,7 @@ add '?/init.server' require 'mmm' require 'lfs' -import Fileder, Key from require 'mmm.mmmfs.fileder' +import Key from require 'mmm.mmmfs.fileder' import SQLStore from require 'mmm.mmmfs.stores.sql' -- usage: diff --git a/build/render_all.moon b/build/render_all.moon index 02da12c..b09957e 100644 --- a/build/render_all.moon +++ b/build/render_all.moon @@ -8,7 +8,7 @@ add '?/init' add '?/init.server' require 'mmm' -import load_tree from require 'mmm.mmmfs.fileder' +import Fileder from require 'mmm.mmmfs.fileder' import get_store from require 'mmm.mmmfs.stores' import render from require 'mmm.mmmfs.layout' @@ -20,7 +20,7 @@ export STATIC STATIC = true store = get_store store -tree = load_tree store +tree = Fileder store tree = tree\walk startpath if startpath for fileder in coroutine.wrap tree\iterate diff --git a/build/server.moon b/build/server.moon index 693f00c..4e7ad3a 100644 --- a/build/server.moon +++ b/build/server.moon @@ -9,7 +9,7 @@ add '?/init.server' require 'mmm' -import Key, dir_base, load_tree from require 'mmm.mmmfs.fileder' +import dir_base, Key, Fileder from require 'mmm.mmmfs.fileder' import convert from require 'mmm.mmmfs.conversion' import get_store from require 'mmm.mmmfs.stores' import render from require 'mmm.mmmfs.layout' @@ -38,7 +38,7 @@ class Server assert @server\loop! handle: (method, path, facet) => - fileder = load_tree @store, path -- @tree\walk path + fileder = Fileder @store, path if not fileder -- fileder not found @@ -50,7 +50,7 @@ class Server when '?interactive' export BROWSER - root = load_tree @store + root = Fileder @store BROWSER = Browser root, path render BROWSER\todom!, fileder, noview: true, scripts: " " + rplc\render! + +if MODE == 'CLIENT' + export ^ + export o + eval = js.global\eval + GRID_W = 50 + GRID_H = 40 + + SVG = + doc: eval "(function() { return SVG(document.createElement('svg')); })", + G: eval "(function() { return new SVG.G(); })", + setmetatable SVG, __call: => @doc! + + o = do + mkobj = eval "(function () { return {}; })" + (tbl) -> + with obj = mkobj! + for k,v in pairs(tbl) + obj[k] = v + + class Diagram + new: (f) => + @svg = SVG! + @arrows = SVG.G! + @width, @height = 0, 0 + @y = 0 + + f @ + + txtattr = o { + fill: 'white', + 'font-size': '14px', + 'text-anchor': 'middle', + } + block: (color, label, h=1) => + @svg\add with SVG.G! + with \rect GRID_W, h * GRID_H + \attr o fill: color + if label + with \plain label + \move GRID_W/2, 0 + \attr txtattr + + \move @width * GRID_W, (@y + h) * -GRID_H + @y += h + if @y > @height + @height = @y + + arrattr = o { + fill: 'white', + 'font-size': '18px', + 'text-anchor': 'middle', + } + arrow: (char, x, y) => + with @arrows\plain char + \attr arrattr + \move (x + 1) * GRID_W, (y - 0.5) * -GRID_H - 11 + + -- inout: (x=@width, y=@y) => @arrow '⇋', x, y -- U+21CB + -- inn: (x=@width, y=@y) => @arrow '↼', x, y+0.25 -- U+21BC + -- out: (x=@width, y=@y) => @arrow '⇁', x, y-0.25 -- U+21C1 + inout: (x=@width, y=@y) => @arrow '⇆', x, y -- U+21C6 + inn: (x=@width, y=@y) => @arrow '←', x, y+0.25 -- U+2190 + out: (x=@width, y=@y) => @arrow '→', x, y-0.25 -- U+2192 + + mind: (label='mind', ...) => @block '#fac710', label, ... + phys: (label='phys', ...) => @block '#8fd13f', label, ... + digi: (label='digi', ...) => @block '#9510ac', label, ... + + next: => + @y = 0 + @width += 1 + + finish: => + return if @node + @svg\add @arrows + + @width += 1 + w, h = @width * GRID_W, @height * GRID_H + + l = GRID_W / 6.5 + @svg\add with @svg\line 0, -GRID_H, w, -GRID_H + \stroke o width: 2, color: '#ffffff', dasharray: "#{l}, #{l}" + + @svg\size w, h + @svg\viewbox 0, -h, w, h + @node = @svg.node + +addlabel = (label, diagram) -> + with div style: { display: 'inline-block', margin: '20px', 'text-align': 'center' } + \append diagram + \append div label + +figures = do + style = + display: 'flex' + 'align-items': 'flex-end' + 'justify-content': 'space-evenly' + (...) -> div { :style, ... } + +sources = do + short = => "#{@id} #{@year}" + long = => @names, " (#{@year}): ", (i @title), ", #{@published}" + { + { + id: 'Milgram', + title: 'Augmented Reality: A class of displays on the reality-virtuality continuum', + published: 'in SPIE Vol. 2351', + names: 'P. Milgram, H. Takemura, A. Utsumi, F. Kishino', + year: 1994 + :long, :short, + }, + { + id: 'Marsh', + title: 'Nested Immersion: Describing and Classifying Augmented Virtual Reality', + published: 'IEEE Virtual Reality Conference 2015', + names: 'W. Marsh, F. Mérienne', + year: 2015 + :long, :short, + }, + { + id: 'Billinghurst', + title: 'The MagicBook: a transitional AR interface', + published: 'in Computer & Graphics 25', + names: 'M. Billinghurst, H. Kato, I. Poupyrev', + year: 2001, + :long, :short, + }, + { + id: 'Matrix', + title: 'The Matrix', + year: 1999, + names: 'L. Wachowski, A. Wachowski', + long: => @names, " (#{@year}): ", (i @title), " (movie)" + short: => tostring @year + }, + { + id: 'Naam', + title: 'Nexus', + published: 'Angry Robot (novel)', + names: 'R. Naam', + year: 2012, + :long, :short, + } + } + +ref = do + fmt = (id) -> + + local src + for _src in *sources + if _src.id == id + src = _src + break + + if src + a { src\short!, href: "##{src.id}" } + else + span id + + ref = (...) -> + refs = { ... } + with span "(", fmt refs[1] + for i=2, #refs + \append ", " + \append fmt refs[i] + \append ")" + +references = -> + with ol! + for src in *sources + \append li { id: src.id, src\long! } + +sect = (label) -> + with section style: 'page-break-inside': 'avoid' + \append h2 label + +append with article style: { margin: 'auto', 'max-width': '750px' } + \append div 'Sol Bekic', style: 'text-align': 'right' + + \append h1 { + style: { 'text-align': 'center', 'font-size': '2em' }, + "Reality Stacks", + div "a Taxonomy for Multi-Reality Experiences", style: 'font-size': '0.6em' + } + + \append with sect "Abstract" + \append p "With the development of mixed-reality experiences and the corresponding interface devices + multiple frameworks for classification of these experiences have been proposed. However these past + attempts have mostly been developed alongside and with the intent of capturing specific projects ", + (ref 'Marsh', 'Billinghurst'), " or are nevertheless very focused on existing methods and technologies ", + (ref 'Milgram'), ". The existing taxonomies also all assume physical reality as a fixpoint and constant and are + thereby not suited to describe many fictional mixed-reality environments and altered states of consciousness. + In this paper we describe a new model for describing such experiences and examplify it's use with currently + existing as well as idealized technologies from popular culture." + + \append with sect "Terminology" + \append p "We propose the following terms and definitions that will be used extensively for the remainder of the paper:" + for definition in *{ + { "layer of reality": "a closed system consisting of a world model and a set of rules or dynamics operating on and + constraining said model." }, + { "world model": "describes a world state containing objects, agents and/or concepts on an arbitrary abstraction level." }, + '------', + { "reality stack": "structure consisting of all layers of reality encoding an agent's interaction with his environment + in their world model at a given moment, as well as all layers supporting these respectively." }, + '------', + { "physical reality": "layer of reality defined by physical matter and the physical laws acting upon it. + While the emergent phenomena of micro- and macro physics as well as layers of social existence etc. may be seen + as separate layers, for the purpose of this paper we will group these together under the term of physical reality." }, + { "mental reality": "layer of reality perceived and processed by the brain of a human agent." }, + { "digital reality": "layer of reality created and simulated by a digital system, e.g. a virtual reality game." }, + { "phys, mind, digi": "abbreviations for physical, mental and digital reality respectively." }, + } + if 'string' == type definition + \append hr! + continue + \append with div style: { 'margin-left': '2rem' } + term = next definition + \append span term, style: { + display: 'inline-block', + 'margin-left': '-2rem', + 'font-weight': 'bold', + 'min-width': '140px' + } + \append span definition[term] + + \append with sect "Introduction" + \append p "We identify two different types of relationships between layers in multi-reality environments. + The first is layer nesting. Layer nesting describes how some layers are contained in other layers; i.e. they exist + within and can be represented fully by the parent layer's world model and the child layer's rules emerge natively from + the parent layer's dynamics. Layer nesting is visualized on the vertical axis in the following diagrams. + For each layer of reality on the bottom of the diagram the nested parent layers can be found by tracing a line upwards + to the top of the diagram. Following a materialistic point of view, physical reality therefore must completely encompass + the top of each diagram." + + \append p "The second type of relationship describes the information flow between a subject and the layers of reality + the subject is immersed in. In a multi-reality experience the subject has access to multiple layers of reality and + their corresponding world models simultaneously.", br!, + "Depending on the specific experience, different types of and directions for information exchange + can exist between these layers and the subject's internal representation of the experience. + For the sake of this paper we distinguish only between ", (i "input"), " and ", (i "output"), " data flow (from the + perspective of the subject); categorized loosely as information the subject receives from the environment + (", (i "input"), ", e.g. visual stimuli) and actions the subject can take to influence the state of the world model + (", (i "output"), ", e.g. motor actions) respectively." + + \append p "In the following diagrams, information flow is visualized horizontally, in the region below the dashed line + at the bottom of the diagram. The subject's internal mental model and layer of reality are placed on the bottom left + side of the diagram. + The layers of reality that the subject experiences directly and that mirror it's internal representations are placed + on the far right. There may be multiple layers of reality sharing this space, visualized as a vertical stack of + layers. Since the subject must necessarily have a complete internal model of the multi-reality experience around + him to feel immersed, the subject's mental layer of reality must span the full height of all the layers visible + on the right side of the diagram.", br!, + "Information flow itself is now visualized concretely using arrows that cross layer boundaries in the lower part of + the diagram as described above. Arrows pointing leftwards denote ", (i "input"), " flow, whilst arrows pointing + rightwards denote ", (i "output"), "-directed information flow. In some cases information doesn't flow directly + between the layers the subject is directly aware of and the subject's internal representation and instead + traverses ", (i "intermediate layers"), " first." + + \append p "Before we take a look at some reality stacks corresponding to current VR and AR technology, + we can take a look at waking life as a baseline stack. To illustrate the format of the diagram we will compare it + to the stack corresponding to a dreaming state:" + + \append with figures! + \append addlabel "Waking Life", Diagram => + @mind! + @inout! + @phys! + + @next! + @phys '', 2 + @finish! + + \append addlabel "Dreaming", Diagram => + @mind! + @phys! + @finish! + + \append p "In both cases, the top of the diagram is fully occupied by the physical layer of reality, colored in green. + This is due to the fact that, according to the materialistic theory of mind, human consciousness owes its existance + to the physical and chemical dynamics of neurons in our brains. Therefore our mental reality must be considered + fully embedded in the physical reality, and consequently it may only appear underneath it in the diagram." + + \append p "During waking life, we concern ourselves mostly with the physical reality surrounding us. + For this reason the physical reality is placed in the lower right corner of the diagram as the layer holding the + external world model relevant to the subject. Information flows in both directions between the physical world model + and the subject's mental model, as denoted by the two white arrows: Information about the state of the world model + enter the subjects mind via the senses (top arrow, pointing leftwards), and choices the subject makes inside of and + based on his mental model can feed back into the physical layer through movements (lower arrow, pointing rightwards)." + + \append p "In the dreaming state on the other hand, the subject is unaware of the physical layer of reality, though + the mind remains embedded inside it. When dreaming, subjects' mental models don't depend on external models, hence + the mental layer of reality must be the only layer along the bottom of the diagram." + + \append with sect "Current Technologies" + \append p "Since recent technological advancements have enabled the development of VR and AR consumer devices, + AR and VR have been established as the potential next frontier of digital entertainment.", br!, + "As the names imply, the notion of reality is at the core of both technologies. + In the following section we will take a look at the respective stacks of both experience types:" + + \append with figures! + \append addlabel "VR", Diagram => + @mind! + @phys! + @inout nil, 1 + + @next! + @phys '', 2 + @inout nil, 1 + + @next! + @digi! + @phys '' + @finish! + + + \append addlabel "AR", Diagram => + @mind! + @inout nil, 1.25 + @inn nil, 0.5 + @phys! + + @next! + @phys '', 2 + @inn nil, .5 + + @next! + @digi nil, .5 + @phys '', 1.5 + @finish! + + \append p "In both cases we find the physical layer of reality as an ", (i "intermediate layer"), " between the mental + and digital layers. Actions taken by the subject have to be acted out physically (corresponding to the + information traversing the barrier between mental and physical reality) before they can be again digitized using + the various tracking and input technologies (which in turn carry the information across the boundary of the physical + and digital spaces)." + + \append p "The difference between AR and VR lies in the fact that in AR the subject experiences a mixture of the + digital and physical world models. This can be seen in the diagram, where we find that right of the diagram origin + and the mental model, the diagram splits and terminates in both layers: while information reaches the subject both + from the digital reality through the physical one, as well as directly from the physical reality, the subject only + directly manipulates state in the physical reality." + + \append p "The data conversions necessary at layer boundaries incur at the least losses in quality and accuracy of + information for purely technical reasons. However ", (i "intermediate layers"), " come at a cost larger than just + an additional step of conversion: + For information to flow through a layer, it must be encodable within that layer’s world model. + This means that the 'weakest link' in a given reality stack determines the upper bound of information possible to + encode within said stack and thereby limits the overall expressivity of the stack.", br!, + "As a practical example we can consider creating an hypothetical VR application that allows users to traverse a + large virtual space by flying. While the human mind is perfectly capable of imagining to fly and control the motion + appropriately, it is extremely hard to devise and implement a satisfying setup and control scheme because the + physical body of the user needs to be taken into account and it, unlike the corresponding representations in the + mental and digital world models, cannot float around freely." + + \append with sect "Future Developments" + \append p "In the previous section we found that the presence of the physical layer in the information path of + VR and AR stacks limits the experience as a whole. It follows that the removal of that indirection should be + an obvious goal for future developments:" + + \append figures addlabel "holy grail of VR: 'The Matrix'", Diagram => + @mind! + @inout! + @phys! + + @next! + @digi! + @phys '' + @finish! + + \append p "In the action movie 'The Matrix' ", (ref 'Matrix'), ", users of the titular VR environment interface with it + by plugging cables into implanted sockets that connect the simulation directly to their central nervous system.", br!, + "While these cables and implanted devices are physical devices, they don't constitute the presence of the + physical layer of reality in the information path because while they do transmit information, the information + remains in either the encoding of the mental model (neural firing patterns) or the encoding of the digital model + (e.g. a numeric encoding of a player character's movement in digital space) and the conversion is made directly + between those two - the data never assumes the native encoding of the physical layer (e.g. as a physical motion)." + + \append p "While we are currently far from being able to read arbitrary high-level information from the brain + or to synthesize sensual input in human perception by bypassing the sensory organs, brain-computer interfaces (BCI) + are a very active area of research with high hopes for comparable achievements in the near future." + + \append p "Applying this same step of removing the physical layer of reality from AR, we end up with something similar + to the nano-particle drug in ", (i "Nexus"), " ", (ref 'Naam'), ". However this does not grant the user a similar + amount of control over his experience as the holy grail of VR does, since the user and the physical part of the + environment remain bound by the physical layer of reality's laws.", br!, + "Instead the holy grail of AR is reached with the creation of a god machine that can manipulate the state of the + physical world according to the user's wishes. In this way the digital and physical realities become unified and + fully 'augmented'." + + \append with figures! + \append addlabel "'Nexus'", Diagram => + @mind! + @inout nil, 0.75 + @inout nil, 1.25 + @phys! + + @next! + @digi nil, .5 + @phys '', 1.5 + @finish! + + \append addlabel "holy grail of AR: 'Deus Machina'", Diagram => + col = '#92807c' + + @mind! + @inout! + @block col, '' + + @next! + @block col, '', 2 + @svg\plain('phys + digi')\attr(o fill: 'white', 'font-size': '14px')\move 6, -2 * GRID_H + @finish! + + \append p "Despite the similarities of VR and AR, the two can be considered polar opposites, as becomes evident when + we compare their respective utopian implementations: they share the goal of allowing us to experience realities + different from the one we naturally inhabit, but while VR seeks to accomplish this by creating a new, nested reality + inside ours, thus giving us full control over it. + AR, on the other hand, is instead an attempt to retrofit our specific needs directly into the very reality we exist + in.", br!, + "This is in direct contrast with the popular notion of the 'reality-virtuality continuum' ", (ref 'Milgram'), ": + the reality-virtuality continuum places common reality and VR (virtuality) as the two extreme poles, while AR + is represented as an intermediate state between the two. Here however we propose to view instead AR and VR as the + respective poles and find instead reality at the centerpoint, where the two opposing influences 'cancel out'." + + \append with sect "Conclusion and Further Work" + \append p "In this paper we have proposed a taxonomy and visualization style for multi-reality experiences, as well + as demonstrated it's flexibility by applying them as examples. Through the application of the proposed theory, + we have also gained a new and contrasting view on preceding work such as the reality-virtuality-continuum. + We have also found that the taxonomy can be used outside the research field of media studies and its use may extend + as far as philosophy of consciousness (see Appendix below)." + + \append p "Further research could enhance the proposed theory with better and more concrete definitions. + In the future, the proposed taxonomy might be used to create a more extensive and complete classification + of reality stacks and to analyse the relationships between them." + + \append with sect 'References' + \append references! + + \append with sect "Appendix: Relation to Theories of Mind" + \append p "This paper starts from a deeply materialistic point of view that borders on microphysicalism. + However it should be noted that the diagram style introduced above lends itself also to display other + philosophical theories of mind. As an example, the following graphics show a typical VR stack as interpreted by + Materialism, Cartesian Dualism and Solipsism respectively:" + + \append with figures! + \append addlabel "VR in Materialism", Diagram => + @mind! + @inout nil, 1 + @phys! + + @next! + @phys '', 2 + @inout nil, 1 + + @next! + @digi! + @phys '' + + @finish! + + \append addlabel "VR in Solipsism", Diagram => + @mind nil, 2 + @inout nil, 1 + + @next! + @digi! + @mind '' + @finish! + + \append addlabel "VR in Cartesian Dualism", Diagram => + @mind nil, 2 + @inout nil, 1 + @next! + + @phys nil, 2 + @inout nil, 1 + @next! + + @digi! + @phys '' + @finish! + + \append p "However these philosophical theories of minds also constitute reality stacks by themselves and as such can + be compared directly:" + + \append with figures! + \append addlabel "Materialism", Diagram => + @mind! + @inout! + @phys! + + @next! + @phys '', 2 + @finish! + + \append addlabel "Solipsism", Diagram => + @mind! + @finish! + + \append addlabel "Cartesian Dualism", Diagram => + @mind! + @inout! + @next! + + @phys! + @finish! + +_content diff --git a/root/articles/realities/text$moonscript -> mmm$dom.moon b/root/articles/realities/text$moonscript -> mmm$dom.moon deleted file mode 100644 index 7689dbb..0000000 --- a/root/articles/realities/text$moonscript -> mmm$dom.moon +++ /dev/null @@ -1,542 +0,0 @@ -import elements from require 'mmm.component' -import h1, h2, p, a, i, div, ol, li, br, hr, span, button, section, article from elements - -_content = div! -append = _content\append - -if MODE == 'SERVER' - export ^ - class Diagram - style = { - display: 'inline-block', - width: '150px', - height: '80px', - 'line-height': '80px', - color: '#fff', - background: '#666', - } - - @id = 1 - new: (@func) => - @id = "diagram-#{@@id}" - @@id += 1 - - render: => - rplc = with div id: @id, :style - \append '(diagram goes here)' - -- \append "" - rplc\render! - -if MODE == 'CLIENT' - export ^ - export o - eval = js.global\eval - GRID_W = 50 - GRID_H = 40 - - SVG = - doc: eval "(function() { return SVG(document.createElement('svg')); })", - G: eval "(function() { return new SVG.G(); })", - setmetatable SVG, __call: => @doc! - - o = do - mkobj = eval "(function () { return {}; })" - (tbl) -> - with obj = mkobj! - for k,v in pairs(tbl) - obj[k] = v - - class Diagram - new: (f) => - @svg = SVG! - @arrows = SVG.G! - @width, @height = 0, 0 - @y = 0 - - f @ - - txtattr = o { - fill: 'white', - 'font-size': '14px', - 'text-anchor': 'middle', - } - block: (color, label, h=1) => - @svg\add with SVG.G! - with \rect GRID_W, h * GRID_H - \attr o fill: color - if label - with \plain label - \move GRID_W/2, 0 - \attr txtattr - - \move @width * GRID_W, (@y + h) * -GRID_H - @y += h - if @y > @height - @height = @y - - arrattr = o { - fill: 'white', - 'font-size': '18px', - 'text-anchor': 'middle', - } - arrow: (char, x, y) => - with @arrows\plain char - \attr arrattr - \move (x + 1) * GRID_W, (y - 0.5) * -GRID_H - 11 - - -- inout: (x=@width, y=@y) => @arrow '⇋', x, y -- U+21CB - -- inn: (x=@width, y=@y) => @arrow '↼', x, y+0.25 -- U+21BC - -- out: (x=@width, y=@y) => @arrow '⇁', x, y-0.25 -- U+21C1 - inout: (x=@width, y=@y) => @arrow '⇆', x, y -- U+21C6 - inn: (x=@width, y=@y) => @arrow '←', x, y+0.25 -- U+2190 - out: (x=@width, y=@y) => @arrow '→', x, y-0.25 -- U+2192 - - mind: (label='mind', ...) => @block '#fac710', label, ... - phys: (label='phys', ...) => @block '#8fd13f', label, ... - digi: (label='digi', ...) => @block '#9510ac', label, ... - - next: => - @y = 0 - @width += 1 - - finish: => - return if @node - @svg\add @arrows - - @width += 1 - w, h = @width * GRID_W, @height * GRID_H - - l = GRID_W / 6.5 - @svg\add with @svg\line 0, -GRID_H, w, -GRID_H - \stroke o width: 2, color: '#ffffff', dasharray: "#{l}, #{l}" - - @svg\size w, h - @svg\viewbox 0, -h, w, h - @node = @svg.node - -addlabel = (label, diagram) -> - with div style: { display: 'inline-block', margin: '20px', 'text-align': 'center' } - \append diagram - \append div label - -figures = do - style = - display: 'flex' - 'align-items': 'flex-end' - 'justify-content': 'space-evenly' - (...) -> div { :style, ... } - -sources = do - short = => "#{@id} #{@year}" - long = => @names, " (#{@year}): ", (i @title), ", #{@published}" - { - { - id: 'Milgram', - title: 'Augmented Reality: A class of displays on the reality-virtuality continuum', - published: 'in SPIE Vol. 2351', - names: 'P. Milgram, H. Takemura, A. Utsumi, F. Kishino', - year: 1994 - :long, :short, - }, - { - id: 'Marsh', - title: 'Nested Immersion: Describing and Classifying Augmented Virtual Reality', - published: 'IEEE Virtual Reality Conference 2015', - names: 'W. Marsh, F. Mérienne', - year: 2015 - :long, :short, - }, - { - id: 'Billinghurst', - title: 'The MagicBook: a transitional AR interface', - published: 'in Computer & Graphics 25', - names: 'M. Billinghurst, H. Kato, I. Poupyrev', - year: 2001, - :long, :short, - }, - { - id: 'Matrix', - title: 'The Matrix', - year: 1999, - names: 'L. Wachowski, A. Wachowski', - long: => @names, " (#{@year}): ", (i @title), " (movie)" - short: => tostring @year - }, - { - id: 'Naam', - title: 'Nexus', - published: 'Angry Robot (novel)', - names: 'R. Naam', - year: 2012, - :long, :short, - } - } - -ref = do - fmt = (id) -> - - local src - for _src in *sources - if _src.id == id - src = _src - break - - if src - a { src\short!, href: "##{src.id}" } - else - span id - - ref = (...) -> - refs = { ... } - with span "(", fmt refs[1] - for i=2, #refs - \append ", " - \append fmt refs[i] - \append ")" - -references = -> - with ol! - for src in *sources - \append li { id: src.id, src\long! } - -sect = (label) -> - with section style: 'page-break-inside': 'avoid' - \append h2 label - -append with article style: { margin: 'auto', 'max-width': '750px' } - \append div 'Sol Bekic', style: 'text-align': 'right' - - \append h1 { - style: { 'text-align': 'center', 'font-size': '2em' }, - "Reality Stacks", - div "a Taxonomy for Multi-Reality Experiences", style: 'font-size': '0.6em' - } - - \append with sect "Abstract" - \append p "With the development of mixed-reality experiences and the corresponding interface devices - multiple frameworks for classification of these experiences have been proposed. However these past - attempts have mostly been developed alongside and with the intent of capturing specific projects ", - (ref 'Marsh', 'Billinghurst'), " or are nevertheless very focused on existing methods and technologies ", - (ref 'Milgram'), ". The existing taxonomies also all assume physical reality as a fixpoint and constant and are - thereby not suited to describe many fictional mixed-reality environments and altered states of consciousness. - In this paper we describe a new model for describing such experiences and examplify it's use with currently - existing as well as idealized technologies from popular culture." - - \append with sect "Terminology" - \append p "We propose the following terms and definitions that will be used extensively for the remainder of the paper:" - for definition in *{ - { "layer of reality": "a closed system consisting of a world model and a set of rules or dynamics operating on and - constraining said model." }, - { "world model": "describes a world state containing objects, agents and/or concepts on an arbitrary abstraction level." }, - '------', - { "reality stack": "structure consisting of all layers of reality encoding an agent's interaction with his environment - in their world model at a given moment, as well as all layers supporting these respectively." }, - '------', - { "physical reality": "layer of reality defined by physical matter and the physical laws acting upon it. - While the emergent phenomena of micro- and macro physics as well as layers of social existence etc. may be seen - as separate layers, for the purpose of this paper we will group these together under the term of physical reality." }, - { "mental reality": "layer of reality perceived and processed by the brain of a human agent." }, - { "digital reality": "layer of reality created and simulated by a digital system, e.g. a virtual reality game." }, - { "phys, mind, digi": "abbreviations for physical, mental and digital reality respectively." }, - } - if 'string' == type definition - \append hr! - continue - \append with div style: { 'margin-left': '2rem' } - term = next definition - \append span term, style: { - display: 'inline-block', - 'margin-left': '-2rem', - 'font-weight': 'bold', - 'min-width': '140px' - } - \append span definition[term] - - \append with sect "Introduction" - \append p "We identify two different types of relationships between layers in multi-reality environments. - The first is layer nesting. Layer nesting describes how some layers are contained in other layers; i.e. they exist - within and can be represented fully by the parent layer's world model and the child layer's rules emerge natively from - the parent layer's dynamics. Layer nesting is visualized on the vertical axis in the following diagrams. - For each layer of reality on the bottom of the diagram the nested parent layers can be found by tracing a line upwards - to the top of the diagram. Following a materialistic point of view, physical reality therefore must completely encompass - the top of each diagram." - - \append p "The second type of relationship describes the information flow between a subject and the layers of reality - the subject is immersed in. In a multi-reality experience the subject has access to multiple layers of reality and - their corresponding world models simultaneously.", br!, - "Depending on the specific experience, different types of and directions for information exchange - can exist between these layers and the subject's internal representation of the experience. - For the sake of this paper we distinguish only between ", (i "input"), " and ", (i "output"), " data flow (from the - perspective of the subject); categorized loosely as information the subject receives from the environment - (", (i "input"), ", e.g. visual stimuli) and actions the subject can take to influence the state of the world model - (", (i "output"), ", e.g. motor actions) respectively." - - \append p "In the following diagrams, information flow is visualized horizontally, in the region below the dashed line - at the bottom of the diagram. The subject's internal mental model and layer of reality are placed on the bottom left - side of the diagram. - The layers of reality that the subject experiences directly and that mirror it's internal representations are placed - on the far right. There may be multiple layers of reality sharing this space, visualized as a vertical stack of - layers. Since the subject must necessarily have a complete internal model of the multi-reality experience around - him to feel immersed, the subject's mental layer of reality must span the full height of all the layers visible - on the right side of the diagram.", br!, - "Information flow itself is now visualized concretely using arrows that cross layer boundaries in the lower part of - the diagram as described above. Arrows pointing leftwards denote ", (i "input"), " flow, whilst arrows pointing - rightwards denote ", (i "output"), "-directed information flow. In some cases information doesn't flow directly - between the layers the subject is directly aware of and the subject's internal representation and instead - traverses ", (i "intermediate layers"), " first." - - \append p "Before we take a look at some reality stacks corresponding to current VR and AR technology, - we can take a look at waking life as a baseline stack. To illustrate the format of the diagram we will compare it - to the stack corresponding to a dreaming state:" - - \append with figures! - \append addlabel "Waking Life", Diagram => - @mind! - @inout! - @phys! - - @next! - @phys '', 2 - @finish! - - \append addlabel "Dreaming", Diagram => - @mind! - @phys! - @finish! - - \append p "In both cases, the top of the diagram is fully occupied by the physical layer of reality, colored in green. - This is due to the fact that, according to the materialistic theory of mind, human consciousness owes its existance - to the physical and chemical dynamics of neurons in our brains. Therefore our mental reality must be considered - fully embedded in the physical reality, and consequently it may only appear underneath it in the diagram." - - \append p "During waking life, we concern ourselves mostly with the physical reality surrounding us. - For this reason the physical reality is placed in the lower right corner of the diagram as the layer holding the - external world model relevant to the subject. Information flows in both directions between the physical world model - and the subject's mental model, as denoted by the two white arrows: Information about the state of the world model - enter the subjects mind via the senses (top arrow, pointing leftwards), and choices the subject makes inside of and - based on his mental model can feed back into the physical layer through movements (lower arrow, pointing rightwards)." - - \append p "In the dreaming state on the other hand, the subject is unaware of the physical layer of reality, though - the mind remains embedded inside it. When dreaming, subjects' mental models don't depend on external models, hence - the mental layer of reality must be the only layer along the bottom of the diagram." - - \append with sect "Current Technologies" - \append p "Since recent technological advancements have enabled the development of VR and AR consumer devices, - AR and VR have been established as the potential next frontier of digital entertainment.", br!, - "As the names imply, the notion of reality is at the core of both technologies. - In the following section we will take a look at the respective stacks of both experience types:" - - \append with figures! - \append addlabel "VR", Diagram => - @mind! - @phys! - @inout nil, 1 - - @next! - @phys '', 2 - @inout nil, 1 - - @next! - @digi! - @phys '' - @finish! - - - \append addlabel "AR", Diagram => - @mind! - @inout nil, 1.25 - @inn nil, 0.5 - @phys! - - @next! - @phys '', 2 - @inn nil, .5 - - @next! - @digi nil, .5 - @phys '', 1.5 - @finish! - - \append p "In both cases we find the physical layer of reality as an ", (i "intermediate layer"), " between the mental - and digital layers. Actions taken by the subject have to be acted out physically (corresponding to the - information traversing the barrier between mental and physical reality) before they can be again digitized using - the various tracking and input technologies (which in turn carry the information across the boundary of the physical - and digital spaces)." - - \append p "The difference between AR and VR lies in the fact that in AR the subject experiences a mixture of the - digital and physical world models. This can be seen in the diagram, where we find that right of the diagram origin - and the mental model, the diagram splits and terminates in both layers: while information reaches the subject both - from the digital reality through the physical one, as well as directly from the physical reality, the subject only - directly manipulates state in the physical reality." - - \append p "The data conversions necessary at layer boundaries incur at the least losses in quality and accuracy of - information for purely technical reasons. However ", (i "intermediate layers"), " come at a cost larger than just - an additional step of conversion: - For information to flow through a layer, it must be encodable within that layer’s world model. - This means that the 'weakest link' in a given reality stack determines the upper bound of information possible to - encode within said stack and thereby limits the overall expressivity of the stack.", br!, - "As a practical example we can consider creating an hypothetical VR application that allows users to traverse a - large virtual space by flying. While the human mind is perfectly capable of imagining to fly and control the motion - appropriately, it is extremely hard to devise and implement a satisfying setup and control scheme because the - physical body of the user needs to be taken into account and it, unlike the corresponding representations in the - mental and digital world models, cannot float around freely." - - \append with sect "Future Developments" - \append p "In the previous section we found that the presence of the physical layer in the information path of - VR and AR stacks limits the experience as a whole. It follows that the removal of that indirection should be - an obvious goal for future developments:" - - \append figures addlabel "holy grail of VR: 'The Matrix'", Diagram => - @mind! - @inout! - @phys! - - @next! - @digi! - @phys '' - @finish! - - \append p "In the action movie 'The Matrix' ", (ref 'Matrix'), ", users of the titular VR environment interface with it - by plugging cables into implanted sockets that connect the simulation directly to their central nervous system.", br!, - "While these cables and implanted devices are physical devices, they don't constitute the presence of the - physical layer of reality in the information path because while they do transmit information, the information - remains in either the encoding of the mental model (neural firing patterns) or the encoding of the digital model - (e.g. a numeric encoding of a player character's movement in digital space) and the conversion is made directly - between those two - the data never assumes the native encoding of the physical layer (e.g. as a physical motion)." - - \append p "While we are currently far from being able to read arbitrary high-level information from the brain - or to synthesize sensual input in human perception by bypassing the sensory organs, brain-computer interfaces (BCI) - are a very active area of research with high hopes for comparable achievements in the near future." - - \append p "Applying this same step of removing the physical layer of reality from AR, we end up with something similar - to the nano-particle drug in ", (i "Nexus"), " ", (ref 'Naam'), ". However this does not grant the user a similar - amount of control over his experience as the holy grail of VR does, since the user and the physical part of the - environment remain bound by the physical layer of reality's laws.", br!, - "Instead the holy grail of AR is reached with the creation of a god machine that can manipulate the state of the - physical world according to the user's wishes. In this way the digital and physical realities become unified and - fully 'augmented'." - - \append with figures! - \append addlabel "'Nexus'", Diagram => - @mind! - @inout nil, 0.75 - @inout nil, 1.25 - @phys! - - @next! - @digi nil, .5 - @phys '', 1.5 - @finish! - - \append addlabel "holy grail of AR: 'Deus Machina'", Diagram => - col = '#92807c' - - @mind! - @inout! - @block col, '' - - @next! - @block col, '', 2 - @svg\plain('phys + digi')\attr(o fill: 'white', 'font-size': '14px')\move 6, -2 * GRID_H - @finish! - - \append p "Despite the similarities of VR and AR, the two can be considered polar opposites, as becomes evident when - we compare their respective utopian implementations: they share the goal of allowing us to experience realities - different from the one we naturally inhabit, but while VR seeks to accomplish this by creating a new, nested reality - inside ours, thus giving us full control over it. - AR, on the other hand, is instead an attempt to retrofit our specific needs directly into the very reality we exist - in.", br!, - "This is in direct contrast with the popular notion of the 'reality-virtuality continuum' ", (ref 'Milgram'), ": - the reality-virtuality continuum places common reality and VR (virtuality) as the two extreme poles, while AR - is represented as an intermediate state between the two. Here however we propose to view instead AR and VR as the - respective poles and find instead reality at the centerpoint, where the two opposing influences 'cancel out'." - - \append with sect "Conclusion and Further Work" - \append p "In this paper we have proposed a taxonomy and visualization style for multi-reality experiences, as well - as demonstrated it's flexibility by applying them as examples. Through the application of the proposed theory, - we have also gained a new and contrasting view on preceding work such as the reality-virtuality-continuum. - We have also found that the taxonomy can be used outside the research field of media studies and its use may extend - as far as philosophy of consciousness (see Appendix below)." - - \append p "Further research could enhance the proposed theory with better and more concrete definitions. - In the future, the proposed taxonomy might be used to create a more extensive and complete classification - of reality stacks and to analyse the relationships between them." - - \append with sect 'References' - \append references! - - \append with sect "Appendix: Relation to Theories of Mind" - \append p "This paper starts from a deeply materialistic point of view that borders on microphysicalism. - However it should be noted that the diagram style introduced above lends itself also to display other - philosophical theories of mind. As an example, the following graphics show a typical VR stack as interpreted by - Materialism, Cartesian Dualism and Solipsism respectively:" - - \append with figures! - \append addlabel "VR in Materialism", Diagram => - @mind! - @inout nil, 1 - @phys! - - @next! - @phys '', 2 - @inout nil, 1 - - @next! - @digi! - @phys '' - - @finish! - - \append addlabel "VR in Solipsism", Diagram => - @mind nil, 2 - @inout nil, 1 - - @next! - @digi! - @mind '' - @finish! - - \append addlabel "VR in Cartesian Dualism", Diagram => - @mind nil, 2 - @inout nil, 1 - @next! - - @phys nil, 2 - @inout nil, 1 - @next! - - @digi! - @phys '' - @finish! - - \append p "However these philosophical theories of minds also constitute reality stacks by themselves and as such can - be compared directly:" - - \append with figures! - \append addlabel "Materialism", Diagram => - @mind! - @inout! - @phys! - - @next! - @phys '', 2 - @finish! - - \append addlabel "Solipsism", Diagram => - @mind! - @finish! - - \append addlabel "Cartesian Dualism", Diagram => - @mind! - @inout! - @next! - - @phys! - @finish! - -_content diff --git a/root/meta/mmm.component/text$moonscript -> fn -> mmm$dom.moon b/root/meta/mmm.component/text$moonscript -> fn -> mmm$dom.moon index ca9a13f..65556c3 100644 --- a/root/meta/mmm.component/text$moonscript -> fn -> mmm$dom.moon +++ b/root/meta/mmm.component/text$moonscript -> fn -> mmm$dom.moon @@ -16,10 +16,6 @@ source = do div the_code, div demo, class: 'example' -raw_find = (fileder, key_pat) -> - for key, val in pairs fileder.facets - return val if key\tostring!\match key_pat - => example = (name) -> for child in *@children diff --git a/root/static/mmm/application$lua.lua b/root/static/mmm/application$lua.lua new file mode 100644 index 0000000..5a6dc53 --- /dev/null +++ b/root/static/mmm/application$lua.lua @@ -0,0 +1,2701 @@ +local p = package.preload +if not p["mmm.canvasapp"] then p["mmm.canvasapp"] = load("local window = js.global\ +local js = require('js')\ +local a, canvas, div, button, script\ +do\ + local _obj_0 = require('mmm.dom')\ + a, canvas, div, button, script = _obj_0.a, _obj_0.canvas, _obj_0.div, _obj_0.button, _obj_0.script\ +end\ +local CanvasApp\ +do\ + local _class_0\ + local _base_0 = {\ + width = 500,\ + height = 400,\ + update = function(self, dt)\ + self.time = self.time + dt\ + if self.length and self.time > self.length then\ + self.time = self.time - self.length\ + return true\ + end\ + end,\ + render = function(self, fps)\ + if fps == nil then\ + fps = 60\ + end\ + assert(self.length, 'cannot render CanvasApp without length set')\ + self.paused = true\ + local actual_render\ + actual_render = function()\ + local writer = js.new(window.Whammy.Video, fps)\ + local doFrame\ + doFrame = function()\ + local done = self:update(1 / fps)\ + self.ctx:resetTransform()\ + self:draw()\ + writer:add(self.canvas)\ + if done or self.time >= self.length then\ + local blob = writer:compile()\ + local name = tostring(self.__class.__name) .. \"_\" .. tostring(fps) .. \"fps.webm\"\ + return self.node.lastChild:appendChild(a(name, {\ + download = name,\ + href = window.URL:createObjectURL(blob)\ + }))\ + else\ + return window:setTimeout(doFrame)\ + end\ + end\ + self.time = 0\ + return doFrame()\ + end\ + if window.Whammy then\ + return actual_render()\ + else\ + window.global = window.global or window\ + return document.body:appendChild(script({\ + onload = actual_render,\ + src = 'https://cdn.jsdelivr.net/npm/whammy@0.0.1/whammy.min.js'\ + }))\ + end\ + end\ + }\ + _base_0.__index = _base_0\ + _class_0 = setmetatable({\ + __init = function(self, show_menu, paused)\ + if show_menu == nil then\ + show_menu = false\ + end\ + self.paused = paused\ + self.canvas = canvas({\ + width = self.width,\ + height = self.height\ + })\ + self.ctx = self.canvas:getContext('2d')\ + self.time = 0\ + self.canvas.tabIndex = 0\ + self.canvas:addEventListener('click', function(_, e)\ + return self.click and self:click(e.offsetX, e.offsetY, e.button)\ + end)\ + self.canvas:addEventListener('keydown', function(_, e)\ + return self.keydown and self:keydown(e.key, e.code)\ + end)\ + local lastMillis = window.performance:now()\ + local animationFrame\ + animationFrame = function(_, millis)\ + self:update((millis - lastMillis) / 1000)\ + self.ctx:resetTransform()\ + self:draw()\ + lastMillis = millis\ + if not self.paused then\ + return window:setTimeout((function()\ + return window:requestAnimationFrame(animationFrame)\ + end), 0)\ + end\ + end\ + window:requestAnimationFrame(animationFrame)\ + if show_menu then\ + self.node = div({\ + className = 'canvas_app',\ + self.canvas,\ + div({\ + className = 'overlay',\ + button('render 30fps', {\ + onclick = function()\ + return self:render(30)\ + end\ + }),\ + button('render 60fps', {\ + onclick = function()\ + return self:render(60)\ + end\ + })\ + })\ + })\ + else\ + self.node = self.canvas\ + end\ + end,\ + __base = _base_0,\ + __name = \"CanvasApp\"\ + }, {\ + __index = _base_0,\ + __call = function(cls, ...)\ + local _self_0 = setmetatable({}, _base_0)\ + cls.__init(_self_0, ...)\ + return _self_0\ + end\ + })\ + _base_0.__class = _class_0\ + CanvasApp = _class_0\ +end\ +return {\ + CanvasApp = CanvasApp\ +}\ +", "mmm/canvasapp.client.lua") end +if not p["mmm.color"] then p["mmm.color"] = load("local rgb\ +rgb = function(r, g, b)\ + if 'table' == type(r) then\ + r, g, b = table.unpack(r)\ + end\ + return \"rgb(\" .. tostring(r * 255) .. \", \" .. tostring(g * 255) .. \", \" .. tostring(b * 255) .. \")\"\ +end\ +local rgba\ +rgba = function(r, g, b, a)\ + if 'table' == type(r) then\ + r, g, b, a = table.unpack(r)\ + end\ + return \"rgba(\" .. tostring(r * 255) .. \", \" .. tostring(g * 255) .. \", \" .. tostring(b * 255) .. \", \" .. tostring(a or 1) .. \")\"\ +end\ +local hsl\ +hsl = function(h, s, l)\ + if 'table' == type(h) then\ + h, s, l = table.unpack(h)\ + end\ + return \"hsl(\" .. tostring(h * 360) .. \", \" .. tostring(s * 100) .. \"%, \" .. tostring(l * 100) .. \"%)\"\ +end\ +local hsla\ +hsla = function(h, s, l, a)\ + if 'table' == type(h) then\ + h, s, l, a = table.unpack(h)\ + end\ + return \"hsla(\" .. tostring(h * 360) .. \", \" .. tostring(s * 100) .. \"%, \" .. tostring(l * 100) .. \"%, \" .. tostring(a or 1) .. \")\"\ +end\ +return {\ + rgb = rgb,\ + rgba = rgba,\ + hsl = hsl,\ + hsla = hsla\ +}\ +", "mmm/color.lua") end +if not p["mmm.highlighting"] then p["mmm.highlighting"] = load("local code\ +code = require('mmm.dom').code\ +local highlight\ +local trim\ +trim = function(str)\ + return str:match('^ *(..-) *$')\ +end\ +if MODE == 'SERVER' then\ + highlight = function(lang, str)\ + assert(str, 'no string to highlight')\ + return code((trim(str)), {\ + class = \"hljs lang-\" .. tostring(lang)\ + })\ + end\ +else\ + highlight = function(lang, str)\ + assert(str, 'no string to highlight')\ + local result = window.hljs:highlight(lang, (trim(str)), true)\ + do\ + local _with_0 = code({\ + class = \"hljs lang-\" .. tostring(lang)\ + })\ + _with_0.innerHTML = result.value\ + return _with_0\ + end\ + end\ +end\ +local languages = setmetatable({ }, {\ + __index = function(self, name)\ + do\ + local val\ + val = function(str)\ + return highlight(name, str)\ + end\ + self[name] = val\ + return val\ + end\ + end\ +})\ +return {\ + highlight = highlight,\ + languages = languages\ +}\ +", "mmm/highlighting.lua") end +if not p["mmm"] then p["mmm"] = load("window = js.global\ +local console\ +document, console = window.document, window.console\ +MODE = 'CLIENT'\ +local deep_tostring\ +deep_tostring = function(tbl, space)\ + if space == nil then\ + space = ''\ + end\ + if 'userdata' == type(tbl) then\ + return tbl\ + end\ + local buf = space .. tostring(tbl)\ + if not ('table' == type(tbl)) then\ + return buf\ + end\ + buf = buf .. ' {\\n'\ + for k, v in pairs(tbl) do\ + buf = buf .. tostring(space) .. \" [\" .. tostring(k) .. \"]: \" .. tostring(deep_tostring(v, space .. ' ')) .. \"\\n\"\ + end\ + buf = buf .. tostring(space) .. \"}\"\ + return buf\ +end\ +print = function(...)\ + local contents\ + do\ + local _accum_0 = { }\ + local _len_0 = 1\ + local _list_0 = {\ + ...\ + }\ + for _index_0 = 1, #_list_0 do\ + local v = _list_0[_index_0]\ + _accum_0[_len_0] = deep_tostring(v)\ + _len_0 = _len_0 + 1\ + end\ + contents = _accum_0\ + end\ + return console:log(table.unpack(contents))\ +end\ +warn = function(...)\ + local contents\ + do\ + local _accum_0 = { }\ + local _len_0 = 1\ + local _list_0 = {\ + ...\ + }\ + for _index_0 = 1, #_list_0 do\ + local v = _list_0[_index_0]\ + _accum_0[_len_0] = deep_tostring(v)\ + _len_0 = _len_0 + 1\ + end\ + contents = _accum_0\ + end\ + return console:warn(table.unpack(contents))\ +end\ +package.path = '/?.lua;/?/init.lua'\ +do\ + local _require = require\ + relative = function(base, sub)\ + if not ('number' == type(sub)) then\ + sub = 0\ + end\ + for i = 1, sub do\ + base = base:match('^(.*)%.%w+$')\ + end\ + return function(name, x)\ + if '.' == name:sub(1, 1) then\ + name = base .. name\ + end\ + return _require(name)\ + end\ + end\ +end\ +if on_load then\ + for _index_0 = 1, #on_load do\ + local f = on_load[_index_0]\ + f()\ + end\ +end\ +on_load = setmetatable({ }, {\ + __newindex = function(t, k, v)\ + rawset(t, k, v)\ + return v()\ + end\ +})\ +", "mmm/init.client.lua") end +if not p["mmm.ordered"] then p["mmm.ordered"] = load("local sort\ +sort = function(t, order_fn, only_strings)\ + do\ + local index\ + do\ + local _accum_0 = { }\ + local _len_0 = 1\ + for k, v in pairs(t) do\ + if (not only_strings) or 'string' == type(k) then\ + _accum_0[_len_0] = k\ + _len_0 = _len_0 + 1\ + end\ + end\ + index = _accum_0\ + end\ + table.sort(index, order_fn)\ + return index\ + end\ +end\ +local onext\ +onext = function(state, key)\ + state.i = state.i + state.step\ + local t, index, i\ + t, index, i = state.t, state.index, state.i\ + do\ + key = index[i]\ + if key then\ + return key, t[key]\ + end\ + end\ +end\ +local opairs\ +opairs = function(t, order_fn, only_strings)\ + if only_strings == nil then\ + only_strings = false\ + end\ + local state = {\ + t = t,\ + i = 0,\ + step = 1,\ + index = sort(t, order_fn, only_strings)\ + }\ + return onext, state, nil\ +end\ +local ropairs\ +ropairs = function(t, order_fn, only_strings)\ + if only_strings == nil then\ + only_strings = false\ + end\ + local index = sort(t, order_fn, only_strings)\ + local state = {\ + t = t,\ + index = index,\ + i = #index + 1,\ + step = -1\ + }\ + return onext, state, nil\ +end\ +return {\ + onext = onext,\ + opairs = opairs,\ + ropairs = ropairs\ +}\ +", "mmm/ordered.lua") end +if not p["mmm.mmmfs.browser"] then p["mmm.mmmfs.browser"] = load("local require = relative(..., 1)\ +local Key\ +Key = require('.fileder').Key\ +local converts, get_conversions, apply_conversions\ +do\ + local _obj_0 = require('.conversion')\ + converts, get_conversions, apply_conversions = _obj_0.converts, _obj_0.get_conversions, _obj_0.apply_conversions\ +end\ +local ReactiveVar, get_or_create, text, elements\ +do\ + local _obj_0 = require('mmm.component')\ + ReactiveVar, get_or_create, text, elements = _obj_0.ReactiveVar, _obj_0.get_or_create, _obj_0.text, _obj_0.elements\ +end\ +local pre, div, nav, span, button, a, code, select, option\ +pre, div, nav, span, button, a, code, select, option = elements.pre, elements.div, elements.nav, elements.span, elements.button, elements.a, elements.code, elements.select, elements.option\ +local languages\ +languages = require('mmm.highlighting').languages\ +local keep\ +keep = function(var)\ + local last = var:get()\ + return var:map(function(val)\ + last = val or last\ + return last\ + end)\ +end\ +local code_cast\ +code_cast = function(lang)\ + return {\ + inp = \"text/\" .. tostring(lang) .. \".*\",\ + out = 'mmm/dom',\ + transform = function(val)\ + return languages[lang](val)\ + end\ + }\ +end\ +local casts = {\ + code_cast('javascript'),\ + code_cast('moonscript'),\ + code_cast('lua'),\ + code_cast('markdown'),\ + code_cast('html'),\ + {\ + inp = 'text/plain',\ + out = 'mmm/dom',\ + transform = function(val)\ + return text(val)\ + end\ + },\ + {\ + inp = 'URL.*',\ + out = 'mmm/dom',\ + transform = function(href)\ + return span(a((code(href)), {\ + href = href\ + }))\ + end\ + }\ +}\ +for _index_0 = 1, #converts do\ + local convert = converts[_index_0]\ + table.insert(casts, convert)\ +end\ +local Browser\ +do\ + local _class_0\ + local err_and_trace, default_convert\ + local _base_0 = {\ + get_content = function(self, prop, err, convert)\ + if err == nil then\ + err = self.error\ + end\ + if convert == nil then\ + convert = default_convert\ + end\ + local clear_error\ + clear_error = function()\ + if MODE == 'CLIENT' then\ + return err:set()\ + end\ + end\ + local disp_error\ + disp_error = function(msg)\ + if MODE == 'CLIENT' then\ + err:set(pre(msg))\ + end\ + warn(\"ERROR rendering content: \" .. tostring(msg))\ + return nil\ + end\ + local active = self.active:get()\ + if not (active) then\ + return disp_error(\"fileder not found!\")\ + end\ + if not (prop) then\ + return disp_error(\"facet not found!\")\ + end\ + local ok, res = xpcall(convert, err_and_trace, active, prop)\ + if MODE == 'CLIENT' then\ + document.body.classList:remove('loading')\ + end\ + if ok and res then\ + clear_error()\ + return res\ + elseif ok then\ + return div(\"[no conversion path to \" .. tostring(prop.type) .. \"]\")\ + elseif res and res.msg.match and res.msg:match('%[nossr%]$') then\ + return div(\"[this page could not be pre-rendered on the server]\")\ + else\ + res = tostring(res.msg) .. \"\\n\" .. tostring(res.trace)\ + return disp_error(res)\ + end\ + end,\ + get_inspector = function(self)\ + self.inspect_prop = self.facet:map(function(prop)\ + local active = self.active:get()\ + local key = active and active:find(prop)\ + if key and key.original then\ + key = key.original\ + end\ + return key\ + end)\ + self.inspect_err = ReactiveVar()\ + do\ + local _with_0 = div({\ + class = 'view inspector'\ + })\ + _with_0:append(nav({\ + span('inspector'),\ + self.inspect_prop:map(function(current)\ + current = current and current:tostring()\ + local fileder = self.active:get()\ + local onchange\ + onchange = function(_, e)\ + if e.target.value == '' then\ + return \ + end\ + local name\ + name = self.facet:get().name\ + return self.inspect_prop:set(Key(e.target.value))\ + end\ + do\ + local _with_1 = select({\ + onchange = onchange\ + })\ + _with_1:append(option('(none)', {\ + value = '',\ + disabled = true,\ + selected = not value\ + }))\ + if fileder then\ + for key, _ in pairs(fileder.facets) do\ + local value = key:tostring()\ + _with_1:append(option(value, {\ + value = value,\ + selected = value == current\ + }))\ + end\ + end\ + return _with_1\ + end\ + end),\ + self.inspect:map(function(enabled)\ + if enabled then\ + return button('close', {\ + onclick = function(_, e)\ + return self.inspect:set(false)\ + end\ + })\ + end\ + end)\ + }))\ + _with_0:append((function()\ + do\ + local _with_1 = div({\ + class = self.inspect_err:map(function(e)\ + if e then\ + return 'error-wrap'\ + else\ + return 'error-wrap empty'\ + end\ + end)\ + })\ + _with_1:append(span(\"an error occured while rendering this view:\"))\ + _with_1:append(self.inspect_err)\ + return _with_1\ + end\ + end)())\ + _with_0:append((function()\ + do\ + local _with_1 = pre({\ + class = 'content'\ + })\ + _with_1:append(keep(self.inspect_prop:map(function(prop, old)\ + return self:get_content(prop, self.inspect_err, function(self, prop)\ + local value, key = self:get(prop)\ + assert(key, \"couldn't @get \" .. tostring(prop))\ + local conversions = get_conversions('mmm/dom', key.type, casts)\ + assert(conversions, \"cannot cast '\" .. tostring(key.type) .. \"'\")\ + return apply_conversions(conversions, value, self, prop)\ + end)\ + end)))\ + return _with_1\ + end\ + end)())\ + return _with_0\ + end\ + end,\ + navigate = function(self, new)\ + return self.path:set(new)\ + end\ + }\ + _base_0.__index = _base_0\ + _class_0 = setmetatable({\ + __init = function(self, root, path, rehydrate)\ + if rehydrate == nil then\ + rehydrate = false\ + end\ + self.root = root\ + assert(self.root, 'root fileder is nil')\ + self.path = ReactiveVar(path or '')\ + if MODE == 'CLIENT' then\ + local logo = document:querySelector('header h1 > svg')\ + local spin\ + spin = function()\ + logo.classList:add('spin')\ + local _ = logo.parentElement.offsetWidth\ + return logo.classList:remove('spin')\ + end\ + self.path:subscribe(function(path)\ + document.body.classList:add('loading')\ + spin()\ + if self.skip then\ + return \ + end\ + local vis_path = path .. ((function()\ + if '/' == path:sub(-1) then\ + return ''\ + else\ + return '/'\ + end\ + end)())\ + return window.history:pushState(path, '', vis_path)\ + end)\ + window.onpopstate = function(_, event)\ + if event.state and not event.state == js.null then\ + self.skip = true\ + self.path:set(event.state)\ + self.skip = nil\ + end\ + end\ + end\ + self.active = self.path:map((function()\ + local _base_1 = self.root\ + local _fn_0 = _base_1.walk\ + return function(...)\ + return _fn_0(_base_1, ...)\ + end\ + end)())\ + self.facet = self.active:map(function(fileder)\ + if not (fileder) then\ + return \ + end\ + local last = self.facet and self.facet:get()\ + return Key((function()\ + if last then\ + return last.type\ + else\ + return 'mmm/dom'\ + end\ + end)())\ + end)\ + self.inspect = ReactiveVar((MODE == 'CLIENT' and window.location.search:match('[?&]inspect')))\ + local main = get_or_create('div', 'browser-root', {\ + class = 'main view'\ + })\ + if MODE == 'SERVER' then\ + main:append(nav({\ + id = 'browser-navbar',\ + span('please stand by... interactivity loading :)')\ + }))\ + else\ + main:prepend((function()\ + do\ + local _with_0 = get_or_create('nav', 'browser-navbar')\ + _with_0.node.innerHTML = ''\ + _with_0:append(span('path: ', self.path:map(function(path)\ + do\ + local _with_1 = div({\ + class = 'path',\ + style = {\ + display = 'inline-block'\ + }\ + })\ + local path_segment\ + path_segment = function(name, href)\ + return a(name, {\ + href = href,\ + onclick = function(_, e)\ + e:preventDefault()\ + return self:navigate(href)\ + end\ + })\ + end\ + local href = ''\ + path = path:match('^/(.*)')\ + _with_1:append(path_segment('root', ''))\ + while path do\ + local name, rest = path:match('^([%w%-_%.]+)/(.*)')\ + if not name then\ + name = path\ + end\ + path = rest\ + href = tostring(href) .. \"/\" .. tostring(name)\ + _with_1:append('/')\ + _with_1:append(path_segment(name, href))\ + end\ + return _with_1\ + end\ + end)))\ + _with_0:append(span('view facet:', {\ + style = {\ + ['margin-right'] = '0'\ + }\ + }))\ + _with_0:append(self.active:map(function(fileder)\ + local onchange\ + onchange = function(_, e)\ + local type\ + type = self.facet:get().type\ + return self.facet:set(Key({\ + name = e.target.value,\ + type = type\ + }))\ + end\ + local current = self.facet:get()\ + current = current and current.name\ + do\ + local _with_1 = select({\ + onchange = onchange,\ + disabled = not fileder\ + })\ + local has_main = fileder and fileder:find(current.name, '.*')\ + _with_1:append(option('(main)', {\ + value = '',\ + disabled = not has_main,\ + selected = current == ''\ + }))\ + if fileder then\ + for i, value in ipairs(fileder:get_facets()) do\ + local _continue_0 = false\ + repeat\ + if value == '' then\ + _continue_0 = true\ + break\ + end\ + _with_1:append(option(value, {\ + value = value,\ + selected = value == current\ + }))\ + _continue_0 = true\ + until true\ + if not _continue_0 then\ + break\ + end\ + end\ + end\ + return _with_1\ + end\ + end))\ + _with_0:append(self.inspect:map(function(enabled)\ + if not enabled then\ + return button('inspect', {\ + onclick = function(_, e)\ + return self.inspect:set(true)\ + end\ + })\ + end\ + end))\ + return _with_0\ + end\ + end)())\ + end\ + self.error = ReactiveVar()\ + main:append((function()\ + do\ + local _with_0 = get_or_create('div', 'browser-error', {\ + class = self.error:map(function(e)\ + if e then\ + return 'error-wrap'\ + else\ + return 'error-wrap empty'\ + end\ + end)\ + })\ + _with_0:append((span(\"an error occured while rendering this view:\")), (rehydrate and _with_0.node.firstChild))\ + _with_0:append(self.error)\ + return _with_0\ + end\ + end)())\ + main:append((function()\ + do\ + local _with_0 = get_or_create('div', 'browser-content', {\ + class = 'content'\ + })\ + local content = ReactiveVar((function()\ + if rehydrate then\ + return _with_0.node.lastChild\ + else\ + return self:get_content(self.facet:get())\ + end\ + end)())\ + _with_0:append(keep(content))\ + if MODE == 'CLIENT' then\ + self.facet:subscribe(function(p)\ + return window:setTimeout((function()\ + return content:set(self:get_content(p))\ + end), 150)\ + end)\ + end\ + return _with_0\ + end\ + end)())\ + if rehydrate then\ + self.facet:set(self.facet:get())\ + end\ + local inspector = self.inspect:map(function(enabled)\ + if enabled then\ + return self:get_inspector()\ + end\ + end)\ + local wrapper = get_or_create('div', 'browser-wrapper', main, inspector, {\ + class = 'browser'\ + })\ + self.node = wrapper.node\ + do\ + local _base_1 = wrapper\ + local _fn_0 = _base_1.render\ + self.render = function(...)\ + return _fn_0(_base_1, ...)\ + end\ + end\ + end,\ + __base = _base_0,\ + __name = \"Browser\"\ + }, {\ + __index = _base_0,\ + __call = function(cls, ...)\ + local _self_0 = setmetatable({}, _base_0)\ + cls.__init(_self_0, ...)\ + return _self_0\ + end\ + })\ + _base_0.__class = _class_0\ + local self = _class_0\ + err_and_trace = function(msg)\ + return {\ + msg = msg,\ + trace = debug.traceback()\ + }\ + end\ + default_convert = function(self, key)\ + return self:get(key.name, 'mmm/dom')\ + end\ + default_convert = function(self, key)\ + return self:get(key.name, 'mmm/dom')\ + end\ + Browser = _class_0\ +end\ +return {\ + Browser = Browser\ +}\ +", "mmm/mmmfs/browser.lua") end +if not p["mmm.mmmfs.conversion"] then p["mmm.mmmfs.conversion"] = load("local require = relative(..., 1)\ +local converts = require('.converts')\ +local count\ +count = function(base, pattern)\ + if pattern == nil then\ + pattern = '->'\ + end\ + return select(2, base:gsub(pattern, ''))\ +end\ +local escape_pattern\ +escape_pattern = function(inp)\ + return \"^\" .. tostring(inp:gsub('([^%w])', '%%%1')) .. \"$\"\ +end\ +local escape_inp\ +escape_inp = function(inp)\ + return \"^\" .. tostring(inp:gsub('([-/])', '%%%1')) .. \"$\"\ +end\ +local get_conversions\ +get_conversions = function(want, have, _converts, limit)\ + if _converts == nil then\ + _converts = converts\ + end\ + if limit == nil then\ + limit = 5\ + end\ + assert(have, 'need starting type(s)')\ + if 'string' == type(have) then\ + have = {\ + have\ + }\ + end\ + assert(#have > 0, 'need starting type(s) (list was empty)')\ + want = escape_pattern(want)\ + local iterations = limit + math.max(table.unpack((function()\ + local _accum_0 = { }\ + local _len_0 = 1\ + for _index_0 = 1, #have do\ + local type = have[_index_0]\ + _accum_0[_len_0] = count(type)\ + _len_0 = _len_0 + 1\ + end\ + return _accum_0\ + end)()))\ + do\ + local _accum_0 = { }\ + local _len_0 = 1\ + for _index_0 = 1, #have do\ + local start = have[_index_0]\ + _accum_0[_len_0] = {\ + start = start,\ + rest = start,\ + conversions = { }\ + }\ + _len_0 = _len_0 + 1\ + end\ + have = _accum_0\ + end\ + for i = 1, iterations do\ + local next_have, c = { }, 1\ + for _index_0 = 1, #have do\ + local _des_0 = have[_index_0]\ + local start, rest, conversions\ + start, rest, conversions = _des_0.start, _des_0.rest, _des_0.conversions\ + if rest:match(want) then\ + return conversions, start\ + else\ + for _index_1 = 1, #_converts do\ + local _continue_0 = false\ + repeat\ + local convert = _converts[_index_1]\ + local inp = escape_inp(convert.inp)\ + if not (rest:match(inp)) then\ + _continue_0 = true\ + break\ + end\ + local result = rest:gsub(inp, convert.out)\ + if result then\ + next_have[c] = {\ + start = start,\ + rest = result,\ + conversions = {\ + {\ + convert = convert,\ + from = rest,\ + to = result\ + },\ + table.unpack(conversions)\ + }\ + }\ + c = c + 1\ + end\ + _continue_0 = true\ + until true\ + if not _continue_0 then\ + break\ + end\ + end\ + end\ + end\ + have = next_have\ + if not (#have > 0) then\ + return \ + end\ + end\ +end\ +local apply_conversions\ +apply_conversions = function(conversions, value, ...)\ + for i = #conversions, 1, -1 do\ + local step = conversions[i]\ + value = step.convert.transform(step, value, ...)\ + end\ + return value\ +end\ +return {\ + converts = converts,\ + get_conversions = get_conversions,\ + apply_conversions = apply_conversions\ +}\ +", "mmm/mmmfs/conversion.lua") end +if not p["mmm.mmmfs.fileder"] then p["mmm.mmmfs.fileder"] = load("local require = relative(..., 1)\ +local get_conversions, apply_conversions\ +do\ + local _obj_0 = require('.conversion')\ + get_conversions, apply_conversions = _obj_0.get_conversions, _obj_0.apply_conversions\ +end\ +local Key\ +do\ + local _class_0\ + local _base_0 = {\ + tostring = function(self)\ + if self.name == '' then\ + return self.type\ + else\ + return tostring(self.name) .. \": \" .. tostring(self.type)\ + end\ + end,\ + __tostring = function(self)\ + return self:tostring()\ + end\ + }\ + _base_0.__index = _base_0\ + _class_0 = setmetatable({\ + __init = function(self, opts, second)\ + if 'string' == type(second) then\ + self.name, self.type = (opts or ''), second\ + elseif 'string' == type(opts) then\ + self.name, self.type = opts:match('^([%w-_]+): *(.+)$')\ + if not self.name then\ + self.name = ''\ + self.type = opts\ + end\ + elseif 'table' == type(opts) then\ + self.name = opts.name\ + self.type = opts.type\ + self.original = opts.original\ + self.filename = opts.filename\ + else\ + return error(\"wrong argument type: \" .. tostring(type(opts)) .. \", \" .. tostring(type(second)))\ + end\ + end,\ + __base = _base_0,\ + __name = \"Key\"\ + }, {\ + __index = _base_0,\ + __call = function(cls, ...)\ + local _self_0 = setmetatable({}, _base_0)\ + cls.__init(_self_0, ...)\ + return _self_0\ + end\ + })\ + _base_0.__class = _class_0\ + Key = _class_0\ +end\ +local Fileder\ +do\ + local _class_0\ + local _base_0 = {\ + walk = function(self, path)\ + if path == '' then\ + return self\ + end\ + if '/' ~= path:sub(1, 1) then\ + path = tostring(self.path) .. \"/\" .. tostring(path)\ + end\ + if not (self.path == path:sub(1, #self.path)) then\ + return \ + end\ + if #path == #self.path then\ + return self\ + end\ + local _list_0 = self.children\ + for _index_0 = 1, #_list_0 do\ + local child = _list_0[_index_0]\ + do\ + local match = child:walk(path)\ + if match then\ + return match\ + end\ + end\ + end\ + end,\ + mount = function(self, path, mount_as)\ + if not mount_as then\ + path = path .. self:gett('name: alpha')\ + end\ + assert(not self.path or self.path == path, \"mounted twice: \" .. tostring(self.path) .. \" and now \" .. tostring(path))\ + self.path = path\ + local _list_0 = self.children\ + for _index_0 = 1, #_list_0 do\ + local child = _list_0[_index_0]\ + child:mount(self.path .. '/')\ + end\ + end,\ + iterate = function(self, depth)\ + if depth == nil then\ + depth = 0\ + end\ + coroutine.yield(self)\ + if depth == 1 then\ + return \ + end\ + local _list_0 = self.children\ + for _index_0 = 1, #_list_0 do\ + local child = _list_0[_index_0]\ + child:iterate(depth - 1)\ + end\ + end,\ + get_facets = function(self)\ + local names = { }\ + for key in pairs(self.facets) do\ + names[key.name] = true\ + end\ + local _accum_0 = { }\ + local _len_0 = 1\ + for name in pairs(names) do\ + _accum_0[_len_0] = name\ + _len_0 = _len_0 + 1\ + end\ + return _accum_0\ + end,\ + has = function(self, ...)\ + local want = Key(...)\ + for key in pairs(self.facets) do\ + local _continue_0 = false\ + repeat\ + if key.original then\ + _continue_0 = true\ + break\ + end\ + if key.name == want.name and key.type == want.type then\ + return key\ + end\ + _continue_0 = true\ + until true\ + if not _continue_0 then\ + break\ + end\ + end\ + end,\ + has_facet = function(self, want)\ + for key in pairs(self.facets) do\ + local _continue_0 = false\ + repeat\ + if key.original then\ + _continue_0 = true\ + break\ + end\ + if key.name == want then\ + return key\ + end\ + _continue_0 = true\ + until true\ + if not _continue_0 then\ + break\ + end\ + end\ + end,\ + find = function(self, ...)\ + local want = Key(...)\ + local matching\ + do\ + local _accum_0 = { }\ + local _len_0 = 1\ + for key in pairs(self.facets) do\ + if key.name == want.name then\ + _accum_0[_len_0] = key\ + _len_0 = _len_0 + 1\ + end\ + end\ + matching = _accum_0\ + end\ + if not (#matching > 0) then\ + return \ + end\ + local shortest_path, start = get_conversions(want.type, (function()\ + local _accum_0 = { }\ + local _len_0 = 1\ + for _index_0 = 1, #matching do\ + local key = matching[_index_0]\ + _accum_0[_len_0] = key.type\ + _len_0 = _len_0 + 1\ + end\ + return _accum_0\ + end)())\ + if start then\ + for _index_0 = 1, #matching do\ + local key = matching[_index_0]\ + if key.type == start then\ + return key, shortest_path\ + end\ + end\ + return error(\"couldn't find key after resolution?\")\ + end\ + end,\ + get = function(self, ...)\ + local want = Key(...)\ + local key, conversions = self:find(want)\ + if key then\ + local value = apply_conversions(conversions, self.facets[key], self, key)\ + return value, key\ + end\ + end,\ + gett = function(self, ...)\ + local want = Key(...)\ + local value, key = self:get(want)\ + assert(value, tostring(self) .. \" doesn't have value for '\" .. tostring(want) .. \"'\")\ + return value, key\ + end,\ + __tostring = function(self)\ + return \"Fileder:\" .. tostring(self.path)\ + end\ + }\ + _base_0.__index = _base_0\ + _class_0 = setmetatable({\ + __init = function(self, facets, children)\ + if not children then\ + do\ + local _accum_0 = { }\ + local _len_0 = 1\ + for i, child in ipairs(facets) do\ + facets[i] = nil\ + local _value_0 = child\ + _accum_0[_len_0] = _value_0\ + _len_0 = _len_0 + 1\ + end\ + children = _accum_0\ + end\ + end\ + self.children = setmetatable({ }, {\ + __index = function(t, k)\ + if not ('string' == type(k)) then\ + return rawget(t, k)\ + end\ + return self:walk(tostring(self.path) .. \"/\" .. tostring(k))\ + end,\ + __newindex = function(t, k, child)\ + rawset(t, k, child)\ + if self.path == '/' then\ + return child:mount('/')\ + elseif self.path then\ + return child:mount(self.path .. '/')\ + end\ + end\ + })\ + for i, child in ipairs(children) do\ + self.children[i] = child\ + end\ + self.facets = setmetatable({ }, {\ + __newindex = function(t, key, v)\ + return rawset(t, (Key(key)), v)\ + end\ + })\ + for k, v in pairs(facets) do\ + self.facets[k] = v\ + end\ + end,\ + __base = _base_0,\ + __name = \"Fileder\"\ + }, {\ + __index = _base_0,\ + __call = function(cls, ...)\ + local _self_0 = setmetatable({}, _base_0)\ + cls.__init(_self_0, ...)\ + return _self_0\ + end\ + })\ + _base_0.__class = _class_0\ + Fileder = _class_0\ +end\ +local dir_base\ +dir_base = function(path)\ + local dir, base = path:match('(.-)([^/]-)$')\ + if dir and #dir > 0 then\ + dir = dir:sub(1, #dir - 1)\ + end\ + return dir, base\ +end\ +local load_tree\ +load_tree = function(store, root)\ + if root == nil then\ + root = ''\ + end\ + local fileders = setmetatable({ }, {\ + __index = function(self, path)\ + do\ + local val = Fileder({ })\ + val.path = path\ + rawset(self, path, val)\ + return val\ + end\ + end\ + })\ + root = fileders[root]\ + root.facets['name: alpha'] = ''\ + for fn, ft in store:list_facets(root.path) do\ + local val = store:load_facet(root.path, fn, ft)\ + root.facets[Key(fn, ft)] = val\ + end\ + for path in store:list_all_fileders(root.path) do\ + local fileder = fileders[path]\ + local parent, name = dir_base(path)\ + fileder.facets['name: alpha'] = name\ + table.insert(fileders[parent].children, fileder)\ + for fn, ft in store:list_facets(path) do\ + local val = store:load_facet(path, fn, ft)\ + fileder.facets[Key(fn, ft)] = val\ + end\ + end\ + return root\ +end\ +return {\ + Key = Key,\ + Fileder = Fileder,\ + dir_base = dir_base,\ + load_tree = load_tree\ +}\ +", "mmm/mmmfs/fileder.lua") end +if not p["mmm.mmmfs"] then p["mmm.mmmfs"] = load("local require = relative(...)\ +local Key, Fileder\ +do\ + local _obj_0 = require('.fileder')\ + Key, Fileder = _obj_0.Key, _obj_0.Fileder\ +end\ +local Browser\ +Browser = require('.browser').Browser\ +return {\ + Key = Key,\ + Fileder = Fileder,\ + Browser = Browser\ +}\ +", "mmm/mmmfs/init.lua") end +if not p["mmm.mmmfs.util"] then p["mmm.mmmfs.util"] = load("local merge\ +merge = function(orig, extra)\ + if orig == nil then\ + orig = { }\ + end\ + do\ + local attr\ + do\ + local _tbl_0 = { }\ + for k, v in pairs(orig) do\ + _tbl_0[k] = v\ + end\ + attr = _tbl_0\ + end\ + for k, v in pairs(extra) do\ + attr[k] = v\ + end\ + return attr\ + end\ +end\ +local tourl\ +tourl = function(path)\ + if STATIC then\ + return path .. '/'\ + else\ + return path .. '/'\ + end\ +end\ +return function(elements)\ + local a, div, pre\ + a, div, pre = elements.a, elements.div, elements.pre\ + local find_fileder\ + find_fileder = function(fileder, origin)\ + if 'string' == type(fileder) then\ + assert(origin, \"cannot resolve path '\" .. tostring(fileder) .. \"' without origin!\")\ + return assert((origin:walk(fileder)), \"couldn't resolve path '\" .. tostring(fileder) .. \"' from \" .. tostring(origin))\ + else\ + return assert(fileder, \"no fileder passed.\")\ + end\ + end\ + local navigate_to\ + navigate_to = function(path, name, opts)\ + if opts == nil then\ + opts = { }\ + end\ + opts.href = tourl(path)\ + if MODE == 'CLIENT' then\ + opts.onclick = function(self, e)\ + e:preventDefault()\ + return BROWSER:navigate(path)\ + end\ + end\ + return a(name, opts)\ + end\ + local link_to\ + link_to = function(fileder, name, origin, attr)\ + fileder = find_fileder(fileder, origin)\ + name = name or fileder:get('title: mmm/dom')\ + name = name or fileder:gett('name: alpha')\ + do\ + local href = fileder:get('link: URL.*')\ + if href then\ + return a(name, merge(attr, {\ + href = href,\ + target = '_blank'\ + }))\ + else\ + return a(name, merge(attr, {\ + href = tourl(fileder.path),\ + onclick = (function()\ + if MODE == 'CLIENT' then\ + return function(self, e)\ + e:preventDefault()\ + return BROWSER:navigate(fileder.path)\ + end\ + end\ + end)()\ + }))\ + end\ + end\ + end\ + local embed\ + embed = function(fileder, name, origin, opts)\ + if name == nil then\ + name = ''\ + end\ + if opts == nil then\ + opts = { }\ + end\ + fileder = find_fileder(fileder, origin)\ + local ok, node = pcall(fileder.gett, fileder, name, 'mmm/dom')\ + if not ok then\ + return div(\"couldn't embed \" .. tostring(fileder) .. \" \" .. tostring(name), (pre(node)), {\ + style = {\ + background = 'var(--gray-fail)',\ + padding = '1em'\ + }\ + })\ + end\ + local klass = 'embed'\ + if opts.desc then\ + klass = klass .. ' desc'\ + end\ + if opts.inline then\ + klass = klass .. ' inline'\ + end\ + node = div({\ + class = klass,\ + node,\ + (function()\ + if opts.desc then\ + return div(opts.desc, {\ + class = 'description'\ + })\ + end\ + end)()\ + })\ + if opts.nolink then\ + return node\ + end\ + return link_to(fileder, node, nil, opts.attr)\ + end\ + return {\ + find_fileder = find_fileder,\ + link_to = link_to,\ + navigate_to = navigate_to,\ + embed = embed\ + }\ +end\ +", "mmm/mmmfs/util.lua") end +if not p["mmm.mmmfs.converts"] then p["mmm.mmmfs.converts"] = load("local require = relative(..., 1)\ +local div, code, img, video, blockquote, a, span, source, iframe\ +do\ + local _obj_0 = require('mmm.dom')\ + div, code, img, video, blockquote, a, span, source, iframe = _obj_0.div, _obj_0.code, _obj_0.img, _obj_0.video, _obj_0.blockquote, _obj_0.a, _obj_0.span, _obj_0.source, _obj_0.iframe\ +end\ +local find_fileder, link_to, embed\ +do\ + local _obj_0 = (require('mmm.mmmfs.util'))(require('mmm.dom'))\ + find_fileder, link_to, embed = _obj_0.find_fileder, _obj_0.link_to, _obj_0.embed\ +end\ +local render\ +render = require('.layout').render\ +local tohtml\ +tohtml = require('mmm.component').tohtml\ +local js_fix\ +if MODE == 'CLIENT' then\ + js_fix = function(arg)\ + if arg == js.null then\ + return \ + end\ + return arg\ + end\ +end\ +local single\ +single = function(func)\ + return function(self, val)\ + return func(val)\ + end\ +end\ +local loadwith\ +loadwith = function(_load)\ + return function(self, val, fileder, key)\ + local func = assert(_load(val, tostring(fileder) .. \"#\" .. tostring(key)))\ + return func()\ + end\ +end\ +local converts = {\ + {\ + inp = 'fn -> (.+)',\ + out = '%1',\ + transform = function(self, val, fileder)\ + return val(fileder)\ + end\ + },\ + {\ + inp = 'mmm/component',\ + out = 'mmm/dom',\ + transform = single(tohtml)\ + },\ + {\ + inp = 'mmm/dom',\ + out = 'text/html+frag',\ + transform = function(self, node)\ + if MODE == 'SERVER' then\ + return node\ + else\ + return node.outerHTML\ + end\ + end\ + },\ + {\ + inp = 'mmm/dom',\ + out = 'text/html',\ + transform = function(self, html, fileder)\ + return render(html, fileder)\ + end\ + },\ + {\ + inp = 'text/html%+frag',\ + out = 'mmm/dom',\ + transform = (function()\ + if MODE == 'SERVER' then\ + return function(self, html, fileder)\ + html = html:gsub('(.-)', function(attrs, text)\ + if #text == 0 then\ + text = nil\ + end\ + local path = ''\ + while attrs and attrs ~= '' do\ + local key, val, _attrs = attrs:match('^(%w+)=\"([^\"]-)\"%s*(.*)')\ + if not key then\ + key, _attrs = attrs:match('^(%w+)%s*(.*)$')\ + val = true\ + end\ + attrs = _attrs\ + local _exp_0 = key\ + if 'path' == _exp_0 then\ + path = val\ + else\ + warn(\"unkown attribute '\" .. tostring(key) .. \"=\\\"\" .. tostring(val) .. \"\\\"' in \")\ + end\ + end\ + return link_to(path, text, fileder)\ + end)\ + html = html:gsub('(.-)', function(attrs, desc)\ + local path, facet = '', ''\ + local opts = { }\ + if #desc ~= 0 then\ + opts.desc = desc\ + end\ + while attrs and attrs ~= '' do\ + local key, val, _attrs = attrs:match('^(%w+)=\"([^\"]-)\"%s*(.*)')\ + if not key then\ + key, _attrs = attrs:match('^(%w+)%s*(.*)$')\ + val = true\ + end\ + attrs = _attrs\ + local _exp_0 = key\ + if 'path' == _exp_0 then\ + path = val\ + elseif 'facet' == _exp_0 then\ + facet = val\ + elseif 'nolink' == _exp_0 then\ + opts.nolink = true\ + elseif 'inline' == _exp_0 then\ + opts.inline = true\ + else\ + warn(\"unkown attribute '\" .. tostring(key) .. \"=\\\"\" .. tostring(val) .. \"\\\"' in \")\ + end\ + end\ + return embed(path, facet, fileder, opts)\ + end)\ + return html\ + end\ + else\ + return function(self, html, fileder)\ + local parent\ + do\ + local _with_0 = document:createElement('div')\ + _with_0.innerHTML = html\ + local embeds = _with_0:getElementsByTagName('mmm-embed')\ + do\ + local _accum_0 = { }\ + local _len_0 = 1\ + for i = 0, embeds.length - 1 do\ + _accum_0[_len_0] = embeds[i]\ + _len_0 = _len_0 + 1\ + end\ + embeds = _accum_0\ + end\ + for _index_0 = 1, #embeds do\ + local element = embeds[_index_0]\ + local path = js_fix(element:getAttribute('path'))\ + local facet = js_fix(element:getAttribute('facet'))\ + local nolink = js_fix(element:getAttribute('nolink'))\ + local inline = js_fix(element:getAttribute('inline'))\ + local desc = js_fix(element.innerText)\ + element:replaceWith(embed(path or '', facet or '', fileder, {\ + nolink = nolink,\ + inline = inline,\ + desc = desc\ + }))\ + end\ + embeds = _with_0:getElementsByTagName('mmm-link')\ + do\ + local _accum_0 = { }\ + local _len_0 = 1\ + for i = 0, embeds.length - 1 do\ + _accum_0[_len_0] = embeds[i]\ + _len_0 = _len_0 + 1\ + end\ + embeds = _accum_0\ + end\ + for _index_0 = 1, #embeds do\ + local element = embeds[_index_0]\ + local text = js_fix(element.innerText)\ + local path = js_fix(element:getAttribute('path'))\ + element:replaceWith(link_to(path or '', text, fileder))\ + end\ + parent = _with_0\ + end\ + assert(1 == parent.childElementCount, \"text/html with more than one child!\")\ + return parent.firstElementChild\ + end\ + end\ + end)()\ + },\ + {\ + inp = 'text/lua -> (.+)',\ + out = '%1',\ + transform = loadwith(load or loadstring)\ + },\ + {\ + inp = 'mmm/tpl -> (.+)',\ + out = '%1',\ + transform = function(self, source, fileder)\ + return source:gsub('{{(.-)}}', function(expr)\ + local path, facet = expr:match('^([%w%-_%./]*)%+(.*)')\ + assert(path, \"couldn't match TPL expression '\" .. tostring(expr) .. \"'\")\ + return (find_fileder(path, fileder)):gett(facet)\ + end)\ + end\ + },\ + {\ + inp = 'time/iso8601-date',\ + out = 'time/unix',\ + transform = function(self, val)\ + local year, _, month, day = val:match('^%s*(%d%d%d%d)(%-?)([01]%d)%2([0-3]%d)%s*$')\ + assert(year, \"failed to parse ISO 8601 date: '\" .. tostring(val) .. \"'\")\ + return os.time({\ + year = year,\ + month = month,\ + day = day\ + })\ + end\ + },\ + {\ + inp = 'URL -> twitter/tweet',\ + out = 'mmm/dom',\ + transform = function(self, href)\ + local id = assert((href:match('twitter.com/[^/]-/status/(%d*)')), \"couldn't parse twitter/tweet URL: '\" .. tostring(href) .. \"'\")\ + if MODE == 'CLIENT' then\ + do\ + local parent = div()\ + window.twttr.widgets:createTweet(id, parent)\ + return parent\ + end\ + else\ + return div(blockquote({\ + class = 'twitter-tweet',\ + ['data-lang'] = 'en',\ + a('(linked tweet)', {\ + href = href\ + })\ + }))\ + end\ + end\ + },\ + {\ + inp = 'URL -> youtube/video',\ + out = 'mmm/dom',\ + transform = function(self, link)\ + local id = link:match('youtu%.be/([^/]+)')\ + id = id or link:match('youtube.com/watch.*[?&]v=([^&]+)')\ + id = id or link:match('youtube.com/[ev]/([^/]+)')\ + id = id or link:match('youtube.com/embed/([^/]+)')\ + assert(id, \"couldn't parse youtube URL: '\" .. tostring(link) .. \"'\")\ + return iframe({\ + width = 560,\ + height = 315,\ + frameborder = 0,\ + allowfullscreen = true,\ + frameBorder = 0,\ + src = \"//www.youtube.com/embed/\" .. tostring(id)\ + })\ + end\ + },\ + {\ + inp = 'URL -> image/.+',\ + out = 'mmm/dom',\ + transform = function(self, src, fileder)\ + return img({\ + src = src\ + })\ + end\ + },\ + {\ + inp = 'URL -> video/.+',\ + out = 'mmm/dom',\ + transform = function(self, src)\ + return video((source({\ + src = src\ + })), {\ + controls = true,\ + loop = true\ + })\ + end\ + },\ + {\ + inp = 'text/plain',\ + out = 'mmm/dom',\ + transform = function(self, val)\ + return span(val)\ + end\ + },\ + {\ + inp = 'alpha',\ + out = 'mmm/dom',\ + transform = single(code)\ + },\ + {\ + inp = '(.+)',\ + out = 'URL -> %1',\ + transform = function(self, _, fileder, key)\ + return tostring(fileder.path) .. \"/\" .. tostring(key.name) .. \":\" .. tostring(self.from)\ + end\ + }\ +}\ +if MODE == 'SERVER' then\ + local ok, moon = pcall(require, 'moonscript.base')\ + if ok then\ + local _load = moon.load or moon.loadstring\ + table.insert(converts, {\ + inp = 'text/moonscript -> (.+)',\ + out = '%1',\ + transform = loadwith(moon.load or moon.loadstring)\ + })\ + table.insert(converts, {\ + inp = 'text/moonscript -> (.+)',\ + out = 'text/lua -> %1',\ + transform = single(moon.to_lua)\ + })\ + end\ +else\ + table.insert(converts, {\ + inp = 'text/javascript -> (.+)',\ + out = '%1',\ + transform = function(self, source)\ + local f = js.new(window.Function, source)\ + return f()\ + end\ + })\ +end\ +do\ + local markdown\ + if MODE == 'SERVER' then\ + local success, discount = pcall(require, 'discount')\ + if not success then\ + warn(\"NO MARKDOWN SUPPORT!\", discount)\ + end\ + markdown = success and function(md)\ + local res = assert(discount.compile(md, 'githubtags'))\ + return res.body\ + end\ + else\ + markdown = window and window.marked and (function()\ + local _base_0 = window\ + local _fn_0 = _base_0.marked\ + return function(...)\ + return _fn_0(_base_0, ...)\ + end\ + end)()\ + end\ + if markdown then\ + table.insert(converts, {\ + inp = 'text/markdown',\ + out = 'text/html+frag',\ + transform = function(self, md)\ + return \"
\" .. tostring(markdown(md)) .. \"
\"\ + end\ + })\ + table.insert(converts, {\ + inp = 'text/markdown%+span',\ + out = 'mmm/dom',\ + transform = (function()\ + if MODE == 'SERVER' then\ + return function(self, source)\ + local html = markdown(source)\ + html = html:gsub('^$', '/span>')\ + end\ + else\ + return function(self, source)\ + local html = markdown(source)\ + html = html:gsub('^%s*

%s*', '')\ + html = html:gsub('%s*

%s*$', '')\ + do\ + local _with_0 = document:createElement('span')\ + _with_0.innerHTML = html\ + return _with_0\ + end\ + end\ + end\ + end)()\ + })\ + end\ +end\ +return converts\ +", "mmm/mmmfs/converts.lua") end +if not p["mmm.mmmfs.layout"] then p["mmm.mmmfs.layout"] = load("local require = relative(..., 1)\ +local header, aside, footer, div, svg, script, g, circle, h1, span, b, a, img\ +do\ + local _obj_0 = require('mmm.dom')\ + header, aside, footer, div, svg, script, g, circle, h1, span, b, a, img = _obj_0.header, _obj_0.aside, _obj_0.footer, _obj_0.div, _obj_0.svg, _obj_0.script, _obj_0.g, _obj_0.circle, _obj_0.h1, _obj_0.span, _obj_0.b, _obj_0.a, _obj_0.img\ +end\ +local navigate_to\ +navigate_to = (require('mmm.mmmfs.util'))(require('mmm.dom')).navigate_to\ +local pick\ +pick = function(...)\ + local num = select('#', ...)\ + local i = math.ceil(math.random() * num)\ + return (select(i, ...))\ +end\ +local iconlink\ +iconlink = function(href, src, alt, style)\ + return a({\ + class = 'iconlink',\ + target = '_blank',\ + rel = 'me',\ + href = href,\ + img({\ + src = src,\ + alt = alt,\ + style = style\ + })\ + })\ +end\ +local logo = svg({\ + class = 'sun',\ + viewBox = '-0.75 -1 1.5 2',\ + xmlns = 'http://www.w3.org/2000/svg',\ + baseProfile = 'full',\ + version = '1.1',\ + g({\ + transform = 'translate(0 .18)',\ + g({\ + class = 'circle out',\ + circle({\ + r = '.6',\ + fill = 'none',\ + ['stroke-width'] = '.12'\ + })\ + }),\ + g({\ + class = 'circle in',\ + circle({\ + r = '.2',\ + stroke = 'none'\ + })\ + })\ + })\ +})\ +local gen_header\ +gen_header = function()\ + return header({\ + div({\ + h1({\ + navigate_to('', logo),\ + span({\ + span('mmm', {\ + class = 'bold'\ + }),\ + '​',\ + '.s‑ol.nu'\ + })\ + }),\ + table.concat({\ + pick('fun', 'cool', 'weird', 'interesting', 'new', 'pleasant'),\ + pick('stuff', 'things', 'projects', 'experiments', 'visuals', 'ideas'),\ + pick(\"with\", 'and'),\ + pick('mostly code', 'code and wires', 'silicon', 'electronics', 'shaders', 'oscilloscopes', 'interfaces', 'hardware', 'FPGAs')\ + }, ' ')\ + }),\ + aside({\ + navigate_to('/about', 'about me'),\ + navigate_to('/games', 'games'),\ + navigate_to('/projects', 'other'),\ + a({\ + href = 'mailto:s%20[removethis]%20[at]%20s-ol.nu',\ + 'contact',\ + script(\"\\n var l = document.currentScript.parentElement;\\n l.href = l.href.replace('%20[at]%20', '@');\\n l.href = l.href.replace('%20[removethis]', '') + '?subject=Hey there :)';\\n \")\ + })\ + })\ + })\ +end\ +footer = footer({\ + span({\ + 'made with \\xe2\\x98\\xbd by ',\ + a('s-ol', {\ + href = 'https://twitter.com/S0lll0s'\ + }),\ + \", \" .. tostring(os.date('%Y'))\ + }),\ + div({\ + class = 'icons',\ + iconlink('https://github.com/s-ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/github.svg', 'github'),\ + iconlink('https://merveilles.town/@s_ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/mastodon.svg', 'mastodon'),\ + iconlink('https://twitter.com/S0lll0s', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/twitter.svg', 'twitter'),\ + iconlink('https://webring.xxiivv.com/#random', 'https://webring.xxiivv.com/icon.black.svg', 'webring', {\ + height = '1.3em',\ + ['margin-left'] = '.3em',\ + ['margin-top'] = '-0.12em'\ + })\ + })\ +})\ +local get_meta\ +get_meta = function(self)\ + local title = (self:get('title: text/plain')) or self:gett('name: alpha')\ + local l\ + l = function(str)\ + str = str:gsub('[%s\\\\n]+$', '')\ + return str:gsub('\\\\n', ' ')\ + end\ + local e\ + e = function(str)\ + return string.format('%q', l(str))\ + end\ + local meta = \"\\n \\n \" .. tostring(l(title)) .. \"\\n \"\ + do\ + local page_meta = self:get('_meta: mmm/dom')\ + if page_meta then\ + meta = meta .. page_meta\ + else\ + meta = meta .. \"\\n \\n\\n \\n \\n \\n \"\ + do\ + local desc = self:get('description: text/plain')\ + if desc then\ + meta = meta .. \"\\n \"\ + end\ + end\ + end\ + end\ + return meta\ +end\ +local render\ +render = function(content, fileder, opts)\ + if opts == nil then\ + opts = { }\ + end\ + opts.meta = opts.meta or get_meta(fileder)\ + opts.scripts = opts.scripts or ''\ + if not (opts.noview) then\ + content = [[
\ +
\ + ]] .. content .. [[
\ +
\ + ]]\ + end\ + local buf = [[\ +\ + \ + \ + \ + ]]\ + buf = buf .. \"\\n \" .. tostring(get_meta(fileder)) .. \"\\n \\n \\n \" .. tostring(gen_header()) .. \"\\n\\n \" .. tostring(content) .. \"\\n\\n \" .. tostring(footer) .. \"\\n \"\ + buf = buf .. [[ \ + \ + \ + \ + \ + \ + \ + ]]\ + buf = buf .. opts.scripts\ + buf = buf .. \"\\n \\n\\n \"\ + return buf\ +end\ +return {\ + render = render\ +}\ +", "mmm/mmmfs/layout.lua") end +if not p["mmm.mmmfs.stores.fs"] then p["mmm.mmmfs.stores.fs"] = load("local lfs = require('lfs')\ +local dir_base\ +dir_base = function(path)\ + local dir, base = path:match('(.-)([^/]-)$')\ + if dir and #dir > 0 then\ + dir = dir:sub(1, #dir - 1)\ + end\ + return dir, base\ +end\ +local FSStore\ +do\ + local _class_0\ + local _base_0 = {\ + log = function(self, ...)\ + return print(\"[DB]\", ...)\ + end,\ + list_fileders_in = function(self, path)\ + if path == nil then\ + path = ''\ + end\ + return coroutine.wrap(function()\ + for entry_name in lfs.dir(self.root .. path) do\ + local _continue_0 = false\ + repeat\ + if '.' == entry_name:sub(1, 1) then\ + _continue_0 = true\ + break\ + end\ + local entry_path = self.root .. tostring(path) .. \"/\" .. tostring(entry_name)\ + if 'directory' == lfs.attributes(entry_path, 'mode') then\ + coroutine.yield(tostring(path) .. \"/\" .. tostring(entry_name))\ + end\ + _continue_0 = true\ + until true\ + if not _continue_0 then\ + break\ + end\ + end\ + end)\ + end,\ + list_all_fileders = function(self, path)\ + if path == nil then\ + path = ''\ + end\ + return coroutine.wrap(function()\ + for path in self:list_fileders_in(path) do\ + coroutine.yield(path)\ + for p in self:list_all_fileders(path) do\ + coroutine.yield(p)\ + end\ + end\ + end)\ + end,\ + create_fileder = function(self, parent, name)\ + self:log(\"creating fileder \" .. tostring(path))\ + local path = tostring(parent) .. \"/\" .. tostring(name)\ + assert(lfs.mkdir(self.root .. path))\ + return path\ + end,\ + remove_fileder = function(self, path)\ + self:log(\"removing fileder \" .. tostring(path))\ + local rmdir\ + rmdir = function(path)\ + for file in lfs.dir(path) do\ + local _continue_0 = false\ + repeat\ + if '.' == file:sub(1, 1) then\ + _continue_0 = true\ + break\ + end\ + local file_path = tostring(path) .. \"/\" .. tostring(file)\ + local _exp_0 = lfs.attributes(file_path, 'mode')\ + if 'file' == _exp_0 then\ + assert(os.remove(file_path))\ + elseif 'directory' == _exp_0 then\ + assert(rmdir(file_path))\ + end\ + _continue_0 = true\ + until true\ + if not _continue_0 then\ + break\ + end\ + end\ + return lfs.rmdir(path)\ + end\ + return rmdir(self.root .. path)\ + end,\ + rename_fileder = function(self, path, next_name)\ + self:log(\"renaming fileder \" .. tostring(path) .. \" -> '\" .. tostring(next_name) .. \"'\")\ + local parent, name = dir_base(path)\ + return assert(os.rename(path, self.root .. tostring(parent) .. \"/\" .. tostring(next_name)))\ + end,\ + move_fileder = function(self, path, next_parent)\ + self:log(\"moving fileder \" .. tostring(path) .. \" -> \" .. tostring(next_parent) .. \"/\")\ + local parent, name = dir_base(path)\ + return assert(os.rename(self.root .. path, self.root .. tostring(next_parent) .. \"/\" .. tostring(name)))\ + end,\ + list_facets = function(self, path)\ + return coroutine.wrap(function()\ + for entry_name in lfs.dir(self.root .. path) do\ + local entry_path = tostring(self.root .. path) .. \"/\" .. tostring(entry_name)\ + if 'file' == lfs.attributes(entry_path, 'mode') then\ + entry_name = (entry_name:match('(.*)%.%w+')) or entry_name\ + entry_name = entry_name:gsub('%$', '/')\ + local name, type = entry_name:match('([%w-_]+): *(.+)')\ + if not name then\ + name = ''\ + type = entry_name\ + end\ + coroutine.yield(name, type)\ + end\ + end\ + end)\ + end,\ + tofp = function(self, path, name, type)\ + if #name > 0 then\ + type = tostring(name) .. \": \" .. tostring(type)\ + end\ + type = type:gsub('%/', '$')\ + return self.root .. tostring(path) .. \"/\" .. tostring(type)\ + end,\ + locate = function(self, path, name, type)\ + if not (lfs.attributes(self.root .. path, 'mode')) then\ + return \ + end\ + type = type:gsub('%/', '$')\ + if #name > 0 then\ + name = tostring(name) .. \": \"\ + end\ + name = name .. type\ + name = name:gsub('([^%w])', '%%%1')\ + local file_name\ + for entry_name in lfs.dir(self.root .. path) do\ + if (entry_name:match(\"^\" .. tostring(name) .. \"$\")) or entry_name:match(\"^\" .. tostring(name) .. \"%.%w+$\") then\ + if file_name then\ + error(\"two files match \" .. tostring(name) .. \": \" .. tostring(file_name) .. \" and \" .. tostring(entry_name) .. \"!\")\ + end\ + file_name = entry_name\ + end\ + end\ + return file_name and self.root .. tostring(path) .. \"/\" .. tostring(file_name)\ + end,\ + load_facet = function(self, path, name, type)\ + local filepath = self:locate(path, name, type)\ + if not (filepath) then\ + return \ + end\ + local file = assert((io.open(filepath, 'rb')), \"couldn't open facet file '\" .. tostring(filepath) .. \"'\")\ + do\ + local _with_0 = file:read('*all')\ + file:close()\ + return _with_0\ + end\ + end,\ + create_facet = function(self, path, name, type, blob)\ + self:log(\"creating facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\ + assert(blob, \"cant create facet without value!\")\ + local filepath = self:tofp(path, name, type)\ + if lfs.attributes(filepath, 'mode') then\ + error(\"facet file already exists!\")\ + end\ + local file = assert((io.open(filepath, 'wb')), \"couldn't open facet file '\" .. tostring(filepath) .. \"'\")\ + file:write(blob)\ + return file:close()\ + end,\ + remove_facet = function(self, path, name, type)\ + self:log(\"removing facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\ + local filepath = self:locate(path, name, type)\ + assert(filepath, \"couldn't locate facet!\")\ + return assert(os.remove(filepath))\ + end,\ + rename_facet = function(self, path, name, type, next_name)\ + self:log(\"renaming facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type) .. \" -> \" .. tostring(next_name))\ + local filepath = self:locate(path, name, type)\ + assert(filepath, \"couldn't locate facet!\")\ + return assert(os.rename(filepath, self:tofp(path, next_name, type)))\ + end,\ + update_facet = function(self, path, name, type, blob)\ + self:log(\"updating facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\ + local filepath = self:locate(path, name, type)\ + assert(filepath, \"couldn't locate facet!\")\ + local file = assert((io.open(filepath, 'wb')), \"couldn't open facet file '\" .. tostring(filepath) .. \"'\")\ + file:write(blob)\ + return file:close()\ + end\ + }\ + _base_0.__index = _base_0\ + _class_0 = setmetatable({\ + __init = function(self, opts)\ + if opts == nil then\ + opts = { }\ + end\ + opts.root = opts.root or 'root'\ + opts.verbose = opts.verbose or false\ + if not opts.verbose then\ + self.log = function() end\ + end\ + self.root = opts.root:match('^(.-)/?$')\ + return self:log(\"opening '\" .. tostring(opts.root) .. \"'...\")\ + end,\ + __base = _base_0,\ + __name = \"FSStore\"\ + }, {\ + __index = _base_0,\ + __call = function(cls, ...)\ + local _self_0 = setmetatable({}, _base_0)\ + cls.__init(_self_0, ...)\ + return _self_0\ + end\ + })\ + _base_0.__class = _class_0\ + FSStore = _class_0\ +end\ +return {\ + FSStore = FSStore\ +}\ +", "mmm/mmmfs/stores/fs.lua") end +if not p["mmm.mmmfs.stores"] then p["mmm.mmmfs.stores"] = load("local require = relative(..., 0)\ +local get_store\ +get_store = function(args, opts)\ + if args == nil then\ + args = 'sql'\ + end\ + if opts == nil then\ + opts = {\ + verbose = true\ + }\ + end\ + local type, arg = args:match('(%w+):(.*)')\ + if not (type) then\ + type = args\ + end\ + local _exp_0 = type:lower()\ + if 'sql' == _exp_0 then\ + local SQLStore\ + SQLStore = require('.sql').SQLStore\ + if arg == 'MEMORY' then\ + opts.memory = true\ + else\ + opts.file = arg\ + end\ + return SQLStore(opts)\ + elseif 'fs' == _exp_0 then\ + local FSStore\ + FSStore = require('.fs').FSStore\ + opts.root = arg\ + return FSStore(opts)\ + else\ + warn(\"unknown or missing value for STORE: valid types values are sql, fs\")\ + return os.exit(1)\ + end\ +end\ +return {\ + get_store = get_store\ +}\ +", "mmm/mmmfs/stores/init.lua") end +if not p["mmm.mmmfs.stores.sql"] then p["mmm.mmmfs.stores.sql"] = load("local sqlite = require('sqlite3')\ +local root = os.tmpname()\ +local SQLStore\ +do\ + local _class_0\ + local _base_0 = {\ + log = function(self, ...)\ + return print(\"[DB]\", ...)\ + end,\ + close = function(self)\ + return self.db:close()\ + end,\ + fetch = function(self, q, ...)\ + local stmt = assert(self.db:prepare(q))\ + if 0 < select('#', ...) then\ + stmt:bind(...)\ + end\ + return stmt:irows()\ + end,\ + fetch_one = function(self, q, ...)\ + local stmt = assert(self.db:prepare(q))\ + if 0 < select('#', ...) then\ + stmt:bind(...)\ + end\ + return stmt:first_irow()\ + end,\ + exec = function(self, q, ...)\ + local stmt = assert(self.db:prepare(q))\ + if 0 < select('#', ...) then\ + stmt:bind(...)\ + end\ + local res = assert(stmt:exec())\ + end,\ + list_fileders_in = function(self, path)\ + if path == nil then\ + path = ''\ + end\ + return coroutine.wrap(function()\ + for _des_0 in self:fetch('SELECT path\\n FROM fileder WHERE parent IS ?', path) do\ + path = _des_0[1]\ + coroutine.yield(path)\ + end\ + end)\ + end,\ + list_all_fileders = function(self, path)\ + if path == nil then\ + path = ''\ + end\ + return coroutine.wrap(function()\ + for path in self:list_fileders_in(path) do\ + coroutine.yield(path)\ + for p in self:list_all_fileders(path) do\ + coroutine.yield(p)\ + end\ + end\ + end)\ + end,\ + create_fileder = function(self, parent, name)\ + local path = tostring(parent) .. \"/\" .. tostring(name)\ + self:log(\"creating fileder \" .. tostring(path))\ + self:exec('INSERT INTO fileder (path, parent)\\n VALUES (:path, :parent)', {\ + path = path,\ + parent = parent\ + })\ + local changes = self:fetch_one('SELECT changes()')\ + assert(changes[1] == 1, \"couldn't create fileder - parent missing?\")\ + return path\ + end,\ + remove_fileder = function(self, path)\ + self:log(\"removing fileder \" .. tostring(path))\ + return self:exec('DELETE FROM fileder\\n WHERE path LIKE :path || \"/%\"\\n OR path = :path', path)\ + end,\ + rename_fileder = function(self, path, next_name)\ + self:log(\"renaming fileder \" .. tostring(path) .. \" -> '\" .. tostring(next_name) .. \"'\")\ + error('not implemented')\ + return self:exec('UPDATE fileder\\n SET path = parent || \"/\" || :next_name\\n WHERE path = :path', {\ + path = path,\ + next_name = next_name\ + })\ + end,\ + move_fileder = function(self, path, next_parent)\ + self:log(\"moving fileder \" .. tostring(path) .. \" -> \" .. tostring(next_parent) .. \"/\")\ + return error('not implemented')\ + end,\ + list_facets = function(self, path)\ + return coroutine.wrap(function()\ + for _des_0 in self:fetch('SELECT facet.name, facet.type\\n FROM facet\\n INNER JOIN fileder ON facet.fileder_id = fileder.id\\n WHERE fileder.path = ?', path) do\ + local name, type\ + name, type = _des_0[1], _des_0[2]\ + coroutine.yield(name, type)\ + end\ + end)\ + end,\ + load_facet = function(self, path, name, type)\ + local v = self:fetch_one('SELECT facet.value\\n FROM facet\\n INNER JOIN fileder ON facet.fileder_id = fileder.id\\n WHERE fileder.path = :path\\n AND facet.name = :name\\n AND facet.type = :type', {\ + path = path,\ + name = name,\ + type = type\ + })\ + return v and v[1]\ + end,\ + create_facet = function(self, path, name, type, blob)\ + self:log(\"creating facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\ + self:exec('INSERT INTO facet (fileder_id, name, type, value)\\n SELECT id, :name, :type, :blob\\n FROM fileder\\n WHERE fileder.path = :path', {\ + path = path,\ + name = name,\ + type = type,\ + blob = blob\ + })\ + local changes = self:fetch_one('SELECT changes()')\ + return assert(changes[1] == 1, \"couldn't create facet - fileder missing?\")\ + end,\ + remove_facet = function(self, path, name, type)\ + self:log(\"removing facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\ + self:exec('DELETE FROM facet\\n WHERE name = :name\\n AND type = :type\\n AND fileder_id = (SELECT id FROM fileder WHERE path = :path)', {\ + path = path,\ + name = name,\ + type = type\ + })\ + local changes = self:fetch_one('SELECT changes()')\ + return assert(changes[1] == 1, \"no such facet\")\ + end,\ + rename_facet = function(self, path, name, type, next_name)\ + self:log(\"renaming facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type) .. \" -> \" .. tostring(next_name))\ + self:exec('UPDATE facet\\n SET name = :next_name\\n WHERE name = :name\\n AND type = :type\\n AND fileder_id = (SELECT id FROM fileder WHERE path = :path)', {\ + path = path,\ + name = name,\ + next_name = next_name,\ + type = type\ + })\ + local changes = self:fetch_one('SELECT changes()')\ + return assert(changes[1] == 1, \"no such facet\")\ + end,\ + update_facet = function(self, path, name, type, blob)\ + self:log(\"updating facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\ + self:exec('UPDATE facet\\n SET value = :blob\\n WHERE facet.name = :name\\n AND facet.type = :type\\n AND facet.fileder_id = (SELECT id FROM fileder WHERE path = :path)', {\ + path = path,\ + name = name,\ + type = type,\ + blob = blob\ + })\ + local changes = self:fetch_one('SELECT changes()')\ + return assert(changes[1] == 1, \"no such facet\")\ + end\ + }\ + _base_0.__index = _base_0\ + _class_0 = setmetatable({\ + __init = function(self, opts)\ + if opts == nil then\ + opts = { }\ + end\ + opts.file = opts.file or 'db.sqlite3'\ + opts.verbose = opts.verbose or false\ + opts.memory = opts.memory or false\ + if not opts.verbose then\ + self.log = function() end\ + end\ + if opts.memory then\ + self:log(\"opening in-memory DB...\")\ + self.db = sqlite.open_memory()\ + else\ + self:log(\"opening '\" .. tostring(opts.file) .. \"'...\")\ + self.db = sqlite.open(opts.file)\ + end\ + return assert(self.db:exec([[ PRAGMA foreign_keys = ON;\ + PRAGMA case_sensitive_like = ON;\ + CREATE TABLE IF NOT EXISTS fileder (\ + id INTEGER NOT NULL PRIMARY KEY,\ + path TEXT NOT NULL UNIQUE,\ + parent TEXT REFERENCES fileder(path)\ + ON DELETE CASCADE\ + ON UPDATE CASCADE\ + );\ + INSERT OR IGNORE INTO fileder (path, parent) VALUES (\"\", NULL);\ +\ + CREATE TABLE IF NOT EXISTS facet (\ + fileder_id INTEGER NOT NULL\ + REFERENCES fileder\ + ON UPDATE CASCADE\ + ON DELETE CASCADE,\ + name TEXT NOT NULL,\ + type TEXT NOT NULL,\ + value BLOB NOT NULL,\ + PRIMARY KEY (fileder_id, name, type)\ + );\ + CREATE INDEX IF NOT EXISTS facet_fileder_id ON facet(fileder_id);\ + CREATE INDEX IF NOT EXISTS facet_name ON facet(name);\ + ]]))\ + end,\ + __base = _base_0,\ + __name = \"SQLStore\"\ + }, {\ + __index = _base_0,\ + __call = function(cls, ...)\ + local _self_0 = setmetatable({}, _base_0)\ + cls.__init(_self_0, ...)\ + return _self_0\ + end\ + })\ + _base_0.__class = _class_0\ + SQLStore = _class_0\ +end\ +return {\ + SQLStore = SQLStore\ +}\ +", "mmm/mmmfs/stores/sql.lua") end +if not p["mmm.dom"] then p["mmm.dom"] = load("local element\ +element = function(element)\ + return function(...)\ + local children = {\ + ...\ + }\ + local attributes = children[#children]\ + if 'table' == (type(attributes)) and not attributes.node then\ + table.remove(children)\ + else\ + attributes = { }\ + end\ + do\ + local e = document:createElement(element)\ + for k, v in pairs(attributes) do\ + if k == 'class' then\ + k = 'className'\ + end\ + if k == 'style' and 'table' == type(v) then\ + for kk, vv in pairs(v) do\ + e.style[kk] = vv\ + end\ + elseif 'string' == type(k) then\ + e[k] = v\ + end\ + end\ + if #children == 0 then\ + children = attributes\ + end\ + for _index_0 = 1, #children do\ + local child = children[_index_0]\ + if 'string' == type(child) then\ + child = document:createTextNode(child)\ + end\ + e:appendChild(child)\ + end\ + return e\ + end\ + end\ +end\ +return setmetatable({ }, {\ + __index = function(self, name)\ + do\ + local val = element(name)\ + self[name] = val\ + return val\ + end\ + end\ +})\ +", "mmm/dom/init.client.lua") end +if not p["mmm.component"] then p["mmm.component"] = load("local tohtml\ +tohtml = function(val)\ + if 'string' == type(val) then\ + return document:createTextNode(val)\ + end\ + if 'table' == type(val) then\ + assert(val.node, \"Table doesn't have .node\")\ + val = val.node\ + end\ + if 'userdata' == type(val) then\ + assert((js.instanceof(val, js.global.Node)), \"userdata is not a Node\")\ + return val\ + else\ + return error(\"not a Node: \" .. tostring(val) .. \", \" .. tostring(type(val)))\ + end\ +end\ +local text\ +text = function(str)\ + return document:createTextNode(tostring(str))\ +end\ +local ReactiveVar\ +do\ + local _class_0\ + local _base_0 = {\ + set = function(self, value)\ + local old = self.value\ + self.value = value\ + for k, callback in pairs(self.listeners) do\ + callback(self.value, old)\ + end\ + end,\ + get = function(self)\ + return self.value\ + end,\ + transform = function(self, transform)\ + return self:set(transform(self:get()))\ + end,\ + subscribe = function(self, callback)\ + do\ + local _with_0\ + _with_0 = function()\ + self.listeners[callback] = nil\ + end\ + self.listeners[callback] = callback\ + return _with_0\ + end\ + end,\ + map = function(self, transform)\ + do\ + local _with_0 = ReactiveVar(transform(self.value))\ + _with_0.upstream = self:subscribe(function(...)\ + return _with_0:set(transform(...))\ + end)\ + return _with_0\ + end\ + end\ + }\ + _base_0.__index = _base_0\ + _class_0 = setmetatable({\ + __init = function(self, value)\ + self.value = value\ + self.listeners = setmetatable({ }, {\ + __mode = 'kv'\ + })\ + end,\ + __base = _base_0,\ + __name = \"ReactiveVar\"\ + }, {\ + __index = _base_0,\ + __call = function(cls, ...)\ + local _self_0 = setmetatable({}, _base_0)\ + cls.__init(_self_0, ...)\ + return _self_0\ + end\ + })\ + _base_0.__class = _class_0\ + local self = _class_0\ + self.isinstance = function(val)\ + return 'table' == (type(val)) and val.subscribe\ + end\ + ReactiveVar = _class_0\ +end\ +local ReactiveElement\ +do\ + local _class_0\ + local _base_0 = {\ + destroy = function(self)\ + local _list_0 = self._subscriptions\ + for _index_0 = 1, #_list_0 do\ + local unsub = _list_0[_index_0]\ + unsub()\ + end\ + end,\ + set = function(self, attr, value)\ + if attr == 'class' then\ + attr = 'className'\ + end\ + if 'table' == (type(value)) and ReactiveVar.isinstance(value) then\ + table.insert(self._subscriptions, value:subscribe(function(...)\ + return self:set(attr, ...)\ + end))\ + value = value:get()\ + end\ + if attr == 'style' and 'table' == type(value) then\ + for k, v in pairs(value) do\ + self.node.style[k] = v\ + end\ + return \ + end\ + self.node[attr] = value\ + end,\ + prepend = function(self, child, last)\ + return self:append(child, last, 'prepend')\ + end,\ + append = function(self, child, last, mode)\ + if mode == nil then\ + mode = 'append'\ + end\ + if ReactiveVar.isinstance(child) then\ + table.insert(self._subscriptions, child:subscribe(function(...)\ + return self:append(...)\ + end))\ + child = child:get()\ + end\ + if 'string' == type(last) then\ + error('cannot replace string node')\ + end\ + if child == nil then\ + if last then\ + self:remove(last)\ + end\ + return \ + end\ + child = tohtml(child)\ + if last then\ + return self.node:replaceChild(child, tohtml(last))\ + else\ + local _exp_0 = mode\ + if 'append' == _exp_0 then\ + return self.node:appendChild(child)\ + elseif 'prepend' == _exp_0 then\ + return self.node:insertBefore(child, self.node.firstChild)\ + end\ + end\ + end,\ + remove = function(self, child)\ + self.node:removeChild(tohtml(child))\ + if 'table' == (type(child)) and child.destroy then\ + return child:destroy()\ + end\ + end\ + }\ + _base_0.__index = _base_0\ + _class_0 = setmetatable({\ + __init = function(self, element, ...)\ + if 'userdata' == type(element) then\ + self.node = element\ + else\ + self.node = document:createElement(element)\ + end\ + self._subscriptions = { }\ + local children = {\ + ...\ + }\ + local attributes = children[#children]\ + if 'table' == (type(attributes)) and (not ReactiveElement.isinstance(attributes)) and (not ReactiveVar.isinstance(attributes)) then\ + table.remove(children)\ + else\ + attributes = { }\ + end\ + for k, v in pairs(attributes) do\ + if 'string' == type(k) then\ + self:set(k, v)\ + end\ + end\ + if #children == 0 then\ + children = attributes\ + end\ + for _index_0 = 1, #children do\ + local child = children[_index_0]\ + self:append(child)\ + end\ + end,\ + __base = _base_0,\ + __name = \"ReactiveElement\"\ + }, {\ + __index = _base_0,\ + __call = function(cls, ...)\ + local _self_0 = setmetatable({}, _base_0)\ + cls.__init(_self_0, ...)\ + return _self_0\ + end\ + })\ + _base_0.__class = _class_0\ + local self = _class_0\ + self.isinstance = function(val)\ + return 'table' == (type(val)) and val.node\ + end\ + ReactiveElement = _class_0\ +end\ +local get_or_create\ +get_or_create = function(elem, id, ...)\ + elem = (document:getElementById(id)) or elem\ + do\ + local _with_0 = ReactiveElement(elem, ...)\ + _with_0:set('id', id)\ + return _with_0\ + end\ +end\ +local elements = setmetatable({ }, {\ + __index = function(self, name)\ + do\ + local val\ + val = function(...)\ + return ReactiveElement(name, ...)\ + end\ + self[name] = val\ + return val\ + end\ + end\ +})\ +return {\ + ReactiveVar = ReactiveVar,\ + ReactiveElement = ReactiveElement,\ + get_or_create = get_or_create,\ + tohtml = tohtml,\ + text = text,\ + elements = elements\ +}\ +", "mmm/component/init.client.lua") end diff --git a/root/static/style/text$css.css b/root/static/style/text$css.css new file mode 100644 index 0000000..c0dc484 --- /dev/null +++ b/root/static/style/text$css.css @@ -0,0 +1,411 @@ +:root { + --gray-bright: #eeeeee; + --gray-dark: #303336; + --gray-darker: #1d1f21; + --gray-neutral: #b9bdc1; + --gray-success: #bdddc1; + --gray-fail: #ddbdc1; + --margin-wide: 2rem; } + @media only screen and (max-width: 425px) { + :root { + --margin-wide: 0.5rem; } } + +* { + font-weight: inherit; + font-style: inherit; + font-family: inherit; + color: inherit; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } + +body, html, h1, h2, h3, h4, h5, h6 { + margin: 0; + padding: 0; } + +h1, h2, h3, h4, h5, h6 { + font-weight: bold; } + +input, select, button { + color: initial; } + +tt, code, kbd, samp { + font-family: monospace; } + +code { + font-size: 0.8em; } + +b, strong { + font-weight: bold; } + +em, i { + font-style: italic; } + +a { + font-size: 1em; + cursor: pointer; } + +hr { + clear: both; } + +ul { + margin: 0; } + +body { + display: flex; + flex-direction: column; + justify-content: space-between; + background: #ffffff; + font-family: sans-serif; + min-height: 100vh; } + +a { + display: inline-block; + font-weight: bold; + text-decoration: underline; + text-decoration-color: transparent; + transition: filter 500ms, text-decoration-color 500ms; } + a:hover { + filter: invert(40%); + text-decoration-color: currentColor; } + +::selection { + background: #303336; + color: #eeeeee; + padding: 1em; } + +/* + +vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid) + +*/ +/*background color*/ +.hljs { + background: #1d1f21; + border-radius: 6px; + padding: 0.2em 0.5em; + white-space: nowrap; } + +pre > .hljs { + display: block; + overflow-x: auto; + padding: 1em; + white-space: pre-wrap; + margin: 0 2em; } + +/*selection color*/ +.hljs::selection, +.hljs span::selection { + background: #373b41; } + +.hljs::-moz-selection, +.hljs span::-moz-selection { + background: #373b41; } + +/*foreground color*/ +.hljs { + color: #c5c8c6; } + +/*color: fg_yellow*/ +.hljs-title, +.hljs-name { + color: #f0c674; } + +/*color: fg_comment*/ +.hljs-comment, +.hljs-meta, +.hljs-meta .hljs-keyword { + color: #707880; } + +/*color: fg_red*/ +.hljs-number, +.hljs-symbol, +.hljs-literal, +.hljs-deletion, +.hljs-link { + color: #cc6666; } + +/*color: fg_green*/ +.hljs-string, +.hljs-doctag, +.hljs-addition, +.hljs-regexp, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #b5bd68; } + +/*color: fg_purple*/ +.hljs-attribute, +.hljs-code, +.hljs-selector-id { + color: #b294bb; } + +/*color: fg_blue*/ +.hljs-keyword, +.hljs-selector-tag, +.hljs-bullet, +.hljs-tag { + color: #81a2be; } + +/*color: fg_aqua*/ +.hljs-subst, +.hljs-variable, +.hljs-template-tag, +.hljs-template-variable { + color: #8abeb7; } + +/*color: fg_orange*/ +.hljs-type, +.hljs-built_in, +.hljs-builtin-name, +.hljs-quote, +.hljs-section, +.hljs-selector-class { + color: #de935f; } + +.hljs-emphasis { + font-style: italic; } + +.hljs-strong { + font-weight: bold; } + +header > div { + font-family: 'Source Sans Pro', sans-serif; + padding: 1rem 2rem; + text-align: right; + color: #eeeeee; + background: #303336; } + header > div h1 { + display: flex; + justify-content: flex-end; + align-items: center; + flex-wrap: wrap; + margin: 0; + line-height: 5rem; + font-size: 4rem; + font-weight: 200; } + header > div h1 > span { + margin-left: auto; } + header > div h1 .bold { + font-weight: 400; } + header > div h1 > a { + height: 5rem; } + header > div h1 .sun { + height: 100%; + stroke: currentColor; + fill: currentColor; } + header > div h1 .sun .out, header > div h1 .sun .in { + animation: spin 2s; + animation-iteration-count: 1; + transform: scale(1); } + header > div h1 .sun .in { + animation: size 2s; } + header > div h1 .sun.spin .circle { + animation: none; } + +header aside { + margin: 0; + padding: 0 2rem; + color: #eeeeee; + background: #1d1f21; + line-height: 3em; } + header aside > a { + margin-right: 2em; } + +@keyframes spin { + 0% { + transform: rotate3d(0.5, 1, 0, 0turn); } + 100% { + transform: rotate3d(0.5, 1, 0, 1turn); } } + +@keyframes size { + 0%, 100% { + transform: scale(1); } + 40%, 60% { + transform: scale(1.8); } } + +footer { + display: flex; + padding: 1rem 2rem; + position: sticky; + bottom: 0; + color: #eeeeee; + background: #303336; } + footer .icons { + flex: 1; + display: flex; + justify-content: flex-end; } + footer .icons .iconlink { + filter: invert(0.7); } + footer .icons .iconlink:hover { + filter: invert(1); } + footer .icons .iconlink > img { + height: 1em; + margin-left: 0.5em; + vertical-align: middle; } + +.browser { + display: flex; + flex: 1; + border-top: 0.2rem solid #eeeeee; } + +.view { + display: flex; + flex-direction: column; + flex: 1 1 0; + min-width: 0; } + .view.inspector { + top: 0; + position: sticky; + max-height: 100vh; + color: #c5c8c6; + border-style: solid; + border-width: 0 0 0 0.6rem; + border-radius: 0 6px 6px 0; + border-color: #303336; + background: #303336; } + .view.inspector nav { + background: inherit; } + .view.inspector .content { + margin: 0; + padding: 0; + display: flex; + background: #1d1f21; } + .view.inspector .content > * { + display: block; + margin: 0; + padding: 1em; + border-radius: 0; + border: 0; + flex: 1; } + .view nav { + position: sticky; + top: 0; + display: flex; + flex: 0 0 auto; + flex-wrap: wrap; + justify-content: space-between; + background: #eeeeee; + z-index: 1000; } + .view nav > span:first-of-type { + flex: 1 0 auto; } + .view nav > * { + margin: 1em; + white-space: nowrap; } + @media only screen and (max-width: 425px) { + .view nav > .inspect-btn { + display: none; } } + .view .error-wrap { + flex: 0 0 auto; + padding: 1em 2em; + overflow: hidden; + background: #ddbdc1; } + .view .error-wrap.empty { + display: none; } + .view .error-wrap > span { + display: inline-block; + margin-bottom: 0.5em; + font-weight: bold; + color: #f00; } + .view .error-wrap > pre { + margin: 0; } + .view .content { + flex: 1 1 auto; + overflow: auto; + padding: 1em 2em; + position: relative; } + +.content { + opacity: 1; + transition: opacity 150ms; } + body.loading .content { + opacity: 0; } + +.content img, .content video { + width: inherit; + height: inherit; } + +.content .markdown > img, .content .markdown > video, +.content .markdown > p > img, +.content .markdown > p > video, +.content .markdown > p > a > img, +.content .markdown > p > a > video, +.content .markdown > a > img, +.content .markdown > a > video { + display: block; + max-width: 100%; + max-height: 50vh; + padding: 0 2em; + box-sizing: border-box; } + +.content .embed { + width: inherit; + height: inherit; } + .content .embed .description { + text-align: center; } + .content .embed.inline { + display: inline-block; } + .content .embed.desc { + display: inline-block; + padding: 0.5em; + margin: 0.2em; + background: #eeeeee; } + +.content pre > code { + border-style: solid; + border-width: 0 0 0 0.6rem; + border-radius: 0 6px 6px 0; + border-color: #303336; + display: block; + border-radius: 6px; + margin: 0 var(--margin-wide); + padding: 1em; + white-space: pre-wrap; + overflow-x: auto; + background: #1d1f21; + color: #c5c8c6; } + +.content pre.dual-code { + display: flex; + justify-content: space-between; + padding: 0 2rem; } + .content pre.dual-code > code { + border-style: solid; + border-width: 0 0.3rem 0 0; + border-radius: 6px 0 0 6px; + flex: 1; + margin: 0; } + .content pre.dual-code > code + code { + border-style: solid; + border-width: 0 0 0 0.3rem; + border-radius: 0 6px 6px 0; } + +.content .example, .content .well { + border-style: solid; + border-width: 0 0 0 0.6rem; + border-radius: 0 6px 6px 0; + margin: 1rem var(--margin-wide); + padding: 1rem; + background: #eeeeee; + border-color: #b9bdc1; } + +.canvas_app { + position: relative; + display: inline-block; } + .canvas_app .overlay { + position: absolute; + padding: 1rem; + top: 0; + left: 0; + right: 0; + bottom: 0; + opacity: 0; + background: rgba(0, 0, 0, 0.7); + transition: opacity 300ms; } + .canvas_app .overlay:hover { + opacity: 1; } + .canvas_app .overlay > * { + margin: 0.5em; } + .canvas_app .overlay a { + display: block; + color: #eeeeee; + font-family: inherit; } -- cgit v1.2.3 From 91546d12919736b08567d7174bf1063cab0838f0 Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 10 Oct 2019 19:39:11 +0200 Subject: add WebStore, fix Browser --- .gitignore | 2 + build/server.moon | 5 +- mmm/mmmfs/browser.moon | 37 +- mmm/mmmfs/fileder.moon | 40 +- mmm/mmmfs/stores/web.moon | 98 ++ root/static/mmm/application$lua.lua | 2701 ----------------------------------- root/static/style/text$css.css | 411 ------ 7 files changed, 123 insertions(+), 3171 deletions(-) create mode 100644 mmm/mmmfs/stores/web.moon delete mode 100644 root/static/mmm/application$lua.lua delete mode 100644 root/static/style/text$css.css diff --git a/.gitignore b/.gitignore index e6facc2..06ed155 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ db.sqlite3 +root/static/style/text$css.css +root/static/mmm/application$lua.lua ##### TUP GITIGNORE ##### ##### Lines below automatically generated by Tup. ##### Do not edit. diff --git a/build/server.moon b/build/server.moon index 4e7ad3a..17c26aa 100644 --- a/build/server.moon +++ b/build/server.moon @@ -58,8 +58,9 @@ class Server table.insert(on_load, function() local path = #{string.format '%q', path} local browser = require 'mmm.mmmfs.browser' - local root = dofile '/$bundle.lua' - root:mount('', true) + local fileder = require 'mmm.mmmfs.fileder' + local web = require 'mmm.mmmfs.stores.web' + local root = fileder.Fileder(web.WebStore({ verbose = true }), path) BROWSER = browser.Browser(root, path, true) end) diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index c71d841..247e36a 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -15,7 +15,7 @@ code_cast = (lang) -> { inp: "text/#{lang}.*", out: 'mmm/dom', - transform: (val) -> languages[lang] val + transform: (val) => languages[lang] val } casts = { @@ -27,12 +27,12 @@ casts = { { inp: 'text/plain' out: 'mmm/dom' - transform: (val) -> text val + transform: (val) => text val }, { inp: 'URL.*' out: 'mmm/dom' - transform: (href) -> span a (code href), :href + transform: (href) => span a (code href), :href }, } @@ -49,7 +49,7 @@ class Browser -- update URL bar if MODE == 'CLIENT' - logo = document\querySelector 'header h1 > svg' + logo = document\querySelector 'header h1 > a > svg' spin = -> logo.classList\add 'spin' logo.parentElement.offsetWidth @@ -115,19 +115,19 @@ class Browser \append span 'view facet:', style: { 'margin-right': '0' } \append @active\map (fileder) -> - onchange = (_, e) -> - { :type } = @facet\get! - @facet\set Key name: e.target.value, :type - - current = @facet\get! - current = current and current.name - with select :onchange, disabled: not fileder - has_main = fileder and fileder\find current.name, '.*' - \append option '(main)', value: '', disabled: not has_main, selected: current == '' - if fileder - for i, value in ipairs fileder\get_facets! - continue if value == '' - \append option value, :value, selected: value == current + onchange = (_, e) -> + { :type } = @facet\get! + @facet\set Key name: e.target.value, :type + + current = @facet\get! + current = current and current.name + with select :onchange, disabled: not fileder + has_main = fileder and fileder\has_facet '' + \append option '(main)', value: '', disabled: not has_main, selected: current == '' + if fileder + for i, value in ipairs fileder\get_facets! + continue if value == '' + \append option value, :value, selected: value == current \append @inspect\map (enabled) -> if not enabled button 'inspect', onclick: (_, e) -> @inspect\set true @@ -215,8 +215,7 @@ class Browser with select :onchange \append option '(none)', value: '', disabled: true, selected: not value if fileder - for i, key in ipairs fileder\get_facets! - value = key\tostring! + for value in pairs fileder.facet_keys \append option value, :value, selected: value == current @inspect\map (enabled) -> if enabled diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index f44bfd0..b7876a3 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -122,7 +122,7 @@ class Fileder for k, v in pairs @facet_keys t[v] - pairs @facets + next, t __newindex: (t, k, v) -> -- get canonical Key instance @@ -131,7 +131,7 @@ class Fileder rawset t, k, v v = k unless v == nil - rawset @facet_keys, k, v + @facet_keys[k] = v } load: => @@ -147,42 +147,6 @@ class Fileder _, name = dir_base @path @facets['name: alpha'] = name - -- -- instantiate from facets and children tables - -- -- or mix in one table (numeric keys are children, remainder facets) - -- -- facet-keys are passed to Key constructor - -- new: (facets, children) => - -- if not children - -- children = for i, child in ipairs facets - -- facets[i] = nil - -- child - - -- -- automatically mount children on insert - -- @children = setmetatable {}, { - -- __index: (t, k) -> - -- return rawget t, k unless 'string' == type k - - -- @walk "#{@path}/#{k}" - - -- __newindex: (t, k, child) -> - -- rawset t, k, child - -- if @path == '/' - -- child\mount '/' - -- elseif @path - -- child\mount @path .. '/' - -- } - - -- -- copy children - -- for i, child in ipairs children - -- @children[i] = child - - -- -- automatically reify string keys on insert - -- @facets = setmetatable {}, __newindex: (t, key, v) -> - -- rawset t, (Key key), v - - -- -- copy facets - -- for k, v in pairs facets - -- @facets[k] = v - -- recursively walk to and return the fileder with @path == path -- * path - the path to walk to walk: (path) => diff --git a/mmm/mmmfs/stores/web.moon b/mmm/mmmfs/stores/web.moon new file mode 100644 index 0000000..adf3ee4 --- /dev/null +++ b/mmm/mmmfs/stores/web.moon @@ -0,0 +1,98 @@ +-- split filename into dirname + basename +dir_base = (path) -> + dir, base = path\match '(.-)([^/]-)$' + if dir and #dir > 0 + dir = dir\sub 1, #dir - 1 + + dir, base + +{ :location, :XMLHttpRequest, :JSON } = js.global +fetch = (url) -> + request = js.new XMLHttpRequest + request\open 'GET', url, false + request\send js.null + + assert request.status == 200, "unexpected status code: #{request.status}" + request.responseText + +class WebStore + new: (opts = {}) => + if MODE == 'CLIENT' + origin = location.origin + opts.host or= origin + opts.verbose or= false + + if not opts.verbose + @log = -> + + -- ensure host ends without a slash + @host = opts.host\match '^(.-)/?$' + @log "connecting to '#{@host}'..." + + log: (...) => + print "[DB]", ... + + -- fileders + list_fileders_in: (path='') => + coroutine.wrap -> + json = fetch "#{@host .. path}/?index: application/json" + index = JSON\parse json + for child in js.of index.children + coroutine.yield child.path + + list_all_fileders: (path='') => + coroutine.wrap -> + for path in @list_fileders_in path + coroutine.yield path + for p in @list_all_fileders path + coroutine.yield p + + create_fileder: (parent, name) => + @log "creating fileder #{path}" + error "not implemented" + + remove_fileder: (path) => + @log "removing fileder #{path}" + error "not implemented" + + rename_fileder: (path, next_name) => + @log "renaming fileder #{path} -> '#{next_name}'" + error "not implemented" + + move_fileder: (path, next_parent) => + @log "moving fileder #{path} -> #{next_parent}/" + error "not implemented" + + -- facets + list_facets: (path) => + coroutine.wrap -> + json = fetch "#{@host .. path}/?index: application/json" + index = JSON\parse json + for facet in js.of index.facets + coroutine.yield facet.name, facet.type + -- @TODO: this doesn't belong here! + if facet.type\match 'text/moonscript' + coroutine.yield facet.name, facet.type\gsub 'text/moonscript', 'text/lua' + + load_facet: (path, name, type) => + fetch "#{@host .. path}/#{name}: #{type}" + + create_facet: (path, name, type, blob) => + @log "creating facet #{path} | #{name}: #{type}" + error "not implemented" + + remove_facet: (path, name, type) => + @log "removing facet #{path} | #{name}: #{type}" + error "not implemented" + + rename_facet: (path, name, type, next_name) => + @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}" + error "not implemented" + + update_facet: (path, name, type, blob) => + @log "updating facet #{path} | #{name}: #{type}" + error "not implemented" + +{ + :WebStore +} diff --git a/root/static/mmm/application$lua.lua b/root/static/mmm/application$lua.lua deleted file mode 100644 index 5a6dc53..0000000 --- a/root/static/mmm/application$lua.lua +++ /dev/null @@ -1,2701 +0,0 @@ -local p = package.preload -if not p["mmm.canvasapp"] then p["mmm.canvasapp"] = load("local window = js.global\ -local js = require('js')\ -local a, canvas, div, button, script\ -do\ - local _obj_0 = require('mmm.dom')\ - a, canvas, div, button, script = _obj_0.a, _obj_0.canvas, _obj_0.div, _obj_0.button, _obj_0.script\ -end\ -local CanvasApp\ -do\ - local _class_0\ - local _base_0 = {\ - width = 500,\ - height = 400,\ - update = function(self, dt)\ - self.time = self.time + dt\ - if self.length and self.time > self.length then\ - self.time = self.time - self.length\ - return true\ - end\ - end,\ - render = function(self, fps)\ - if fps == nil then\ - fps = 60\ - end\ - assert(self.length, 'cannot render CanvasApp without length set')\ - self.paused = true\ - local actual_render\ - actual_render = function()\ - local writer = js.new(window.Whammy.Video, fps)\ - local doFrame\ - doFrame = function()\ - local done = self:update(1 / fps)\ - self.ctx:resetTransform()\ - self:draw()\ - writer:add(self.canvas)\ - if done or self.time >= self.length then\ - local blob = writer:compile()\ - local name = tostring(self.__class.__name) .. \"_\" .. tostring(fps) .. \"fps.webm\"\ - return self.node.lastChild:appendChild(a(name, {\ - download = name,\ - href = window.URL:createObjectURL(blob)\ - }))\ - else\ - return window:setTimeout(doFrame)\ - end\ - end\ - self.time = 0\ - return doFrame()\ - end\ - if window.Whammy then\ - return actual_render()\ - else\ - window.global = window.global or window\ - return document.body:appendChild(script({\ - onload = actual_render,\ - src = 'https://cdn.jsdelivr.net/npm/whammy@0.0.1/whammy.min.js'\ - }))\ - end\ - end\ - }\ - _base_0.__index = _base_0\ - _class_0 = setmetatable({\ - __init = function(self, show_menu, paused)\ - if show_menu == nil then\ - show_menu = false\ - end\ - self.paused = paused\ - self.canvas = canvas({\ - width = self.width,\ - height = self.height\ - })\ - self.ctx = self.canvas:getContext('2d')\ - self.time = 0\ - self.canvas.tabIndex = 0\ - self.canvas:addEventListener('click', function(_, e)\ - return self.click and self:click(e.offsetX, e.offsetY, e.button)\ - end)\ - self.canvas:addEventListener('keydown', function(_, e)\ - return self.keydown and self:keydown(e.key, e.code)\ - end)\ - local lastMillis = window.performance:now()\ - local animationFrame\ - animationFrame = function(_, millis)\ - self:update((millis - lastMillis) / 1000)\ - self.ctx:resetTransform()\ - self:draw()\ - lastMillis = millis\ - if not self.paused then\ - return window:setTimeout((function()\ - return window:requestAnimationFrame(animationFrame)\ - end), 0)\ - end\ - end\ - window:requestAnimationFrame(animationFrame)\ - if show_menu then\ - self.node = div({\ - className = 'canvas_app',\ - self.canvas,\ - div({\ - className = 'overlay',\ - button('render 30fps', {\ - onclick = function()\ - return self:render(30)\ - end\ - }),\ - button('render 60fps', {\ - onclick = function()\ - return self:render(60)\ - end\ - })\ - })\ - })\ - else\ - self.node = self.canvas\ - end\ - end,\ - __base = _base_0,\ - __name = \"CanvasApp\"\ - }, {\ - __index = _base_0,\ - __call = function(cls, ...)\ - local _self_0 = setmetatable({}, _base_0)\ - cls.__init(_self_0, ...)\ - return _self_0\ - end\ - })\ - _base_0.__class = _class_0\ - CanvasApp = _class_0\ -end\ -return {\ - CanvasApp = CanvasApp\ -}\ -", "mmm/canvasapp.client.lua") end -if not p["mmm.color"] then p["mmm.color"] = load("local rgb\ -rgb = function(r, g, b)\ - if 'table' == type(r) then\ - r, g, b = table.unpack(r)\ - end\ - return \"rgb(\" .. tostring(r * 255) .. \", \" .. tostring(g * 255) .. \", \" .. tostring(b * 255) .. \")\"\ -end\ -local rgba\ -rgba = function(r, g, b, a)\ - if 'table' == type(r) then\ - r, g, b, a = table.unpack(r)\ - end\ - return \"rgba(\" .. tostring(r * 255) .. \", \" .. tostring(g * 255) .. \", \" .. tostring(b * 255) .. \", \" .. tostring(a or 1) .. \")\"\ -end\ -local hsl\ -hsl = function(h, s, l)\ - if 'table' == type(h) then\ - h, s, l = table.unpack(h)\ - end\ - return \"hsl(\" .. tostring(h * 360) .. \", \" .. tostring(s * 100) .. \"%, \" .. tostring(l * 100) .. \"%)\"\ -end\ -local hsla\ -hsla = function(h, s, l, a)\ - if 'table' == type(h) then\ - h, s, l, a = table.unpack(h)\ - end\ - return \"hsla(\" .. tostring(h * 360) .. \", \" .. tostring(s * 100) .. \"%, \" .. tostring(l * 100) .. \"%, \" .. tostring(a or 1) .. \")\"\ -end\ -return {\ - rgb = rgb,\ - rgba = rgba,\ - hsl = hsl,\ - hsla = hsla\ -}\ -", "mmm/color.lua") end -if not p["mmm.highlighting"] then p["mmm.highlighting"] = load("local code\ -code = require('mmm.dom').code\ -local highlight\ -local trim\ -trim = function(str)\ - return str:match('^ *(..-) *$')\ -end\ -if MODE == 'SERVER' then\ - highlight = function(lang, str)\ - assert(str, 'no string to highlight')\ - return code((trim(str)), {\ - class = \"hljs lang-\" .. tostring(lang)\ - })\ - end\ -else\ - highlight = function(lang, str)\ - assert(str, 'no string to highlight')\ - local result = window.hljs:highlight(lang, (trim(str)), true)\ - do\ - local _with_0 = code({\ - class = \"hljs lang-\" .. tostring(lang)\ - })\ - _with_0.innerHTML = result.value\ - return _with_0\ - end\ - end\ -end\ -local languages = setmetatable({ }, {\ - __index = function(self, name)\ - do\ - local val\ - val = function(str)\ - return highlight(name, str)\ - end\ - self[name] = val\ - return val\ - end\ - end\ -})\ -return {\ - highlight = highlight,\ - languages = languages\ -}\ -", "mmm/highlighting.lua") end -if not p["mmm"] then p["mmm"] = load("window = js.global\ -local console\ -document, console = window.document, window.console\ -MODE = 'CLIENT'\ -local deep_tostring\ -deep_tostring = function(tbl, space)\ - if space == nil then\ - space = ''\ - end\ - if 'userdata' == type(tbl) then\ - return tbl\ - end\ - local buf = space .. tostring(tbl)\ - if not ('table' == type(tbl)) then\ - return buf\ - end\ - buf = buf .. ' {\\n'\ - for k, v in pairs(tbl) do\ - buf = buf .. tostring(space) .. \" [\" .. tostring(k) .. \"]: \" .. tostring(deep_tostring(v, space .. ' ')) .. \"\\n\"\ - end\ - buf = buf .. tostring(space) .. \"}\"\ - return buf\ -end\ -print = function(...)\ - local contents\ - do\ - local _accum_0 = { }\ - local _len_0 = 1\ - local _list_0 = {\ - ...\ - }\ - for _index_0 = 1, #_list_0 do\ - local v = _list_0[_index_0]\ - _accum_0[_len_0] = deep_tostring(v)\ - _len_0 = _len_0 + 1\ - end\ - contents = _accum_0\ - end\ - return console:log(table.unpack(contents))\ -end\ -warn = function(...)\ - local contents\ - do\ - local _accum_0 = { }\ - local _len_0 = 1\ - local _list_0 = {\ - ...\ - }\ - for _index_0 = 1, #_list_0 do\ - local v = _list_0[_index_0]\ - _accum_0[_len_0] = deep_tostring(v)\ - _len_0 = _len_0 + 1\ - end\ - contents = _accum_0\ - end\ - return console:warn(table.unpack(contents))\ -end\ -package.path = '/?.lua;/?/init.lua'\ -do\ - local _require = require\ - relative = function(base, sub)\ - if not ('number' == type(sub)) then\ - sub = 0\ - end\ - for i = 1, sub do\ - base = base:match('^(.*)%.%w+$')\ - end\ - return function(name, x)\ - if '.' == name:sub(1, 1) then\ - name = base .. name\ - end\ - return _require(name)\ - end\ - end\ -end\ -if on_load then\ - for _index_0 = 1, #on_load do\ - local f = on_load[_index_0]\ - f()\ - end\ -end\ -on_load = setmetatable({ }, {\ - __newindex = function(t, k, v)\ - rawset(t, k, v)\ - return v()\ - end\ -})\ -", "mmm/init.client.lua") end -if not p["mmm.ordered"] then p["mmm.ordered"] = load("local sort\ -sort = function(t, order_fn, only_strings)\ - do\ - local index\ - do\ - local _accum_0 = { }\ - local _len_0 = 1\ - for k, v in pairs(t) do\ - if (not only_strings) or 'string' == type(k) then\ - _accum_0[_len_0] = k\ - _len_0 = _len_0 + 1\ - end\ - end\ - index = _accum_0\ - end\ - table.sort(index, order_fn)\ - return index\ - end\ -end\ -local onext\ -onext = function(state, key)\ - state.i = state.i + state.step\ - local t, index, i\ - t, index, i = state.t, state.index, state.i\ - do\ - key = index[i]\ - if key then\ - return key, t[key]\ - end\ - end\ -end\ -local opairs\ -opairs = function(t, order_fn, only_strings)\ - if only_strings == nil then\ - only_strings = false\ - end\ - local state = {\ - t = t,\ - i = 0,\ - step = 1,\ - index = sort(t, order_fn, only_strings)\ - }\ - return onext, state, nil\ -end\ -local ropairs\ -ropairs = function(t, order_fn, only_strings)\ - if only_strings == nil then\ - only_strings = false\ - end\ - local index = sort(t, order_fn, only_strings)\ - local state = {\ - t = t,\ - index = index,\ - i = #index + 1,\ - step = -1\ - }\ - return onext, state, nil\ -end\ -return {\ - onext = onext,\ - opairs = opairs,\ - ropairs = ropairs\ -}\ -", "mmm/ordered.lua") end -if not p["mmm.mmmfs.browser"] then p["mmm.mmmfs.browser"] = load("local require = relative(..., 1)\ -local Key\ -Key = require('.fileder').Key\ -local converts, get_conversions, apply_conversions\ -do\ - local _obj_0 = require('.conversion')\ - converts, get_conversions, apply_conversions = _obj_0.converts, _obj_0.get_conversions, _obj_0.apply_conversions\ -end\ -local ReactiveVar, get_or_create, text, elements\ -do\ - local _obj_0 = require('mmm.component')\ - ReactiveVar, get_or_create, text, elements = _obj_0.ReactiveVar, _obj_0.get_or_create, _obj_0.text, _obj_0.elements\ -end\ -local pre, div, nav, span, button, a, code, select, option\ -pre, div, nav, span, button, a, code, select, option = elements.pre, elements.div, elements.nav, elements.span, elements.button, elements.a, elements.code, elements.select, elements.option\ -local languages\ -languages = require('mmm.highlighting').languages\ -local keep\ -keep = function(var)\ - local last = var:get()\ - return var:map(function(val)\ - last = val or last\ - return last\ - end)\ -end\ -local code_cast\ -code_cast = function(lang)\ - return {\ - inp = \"text/\" .. tostring(lang) .. \".*\",\ - out = 'mmm/dom',\ - transform = function(val)\ - return languages[lang](val)\ - end\ - }\ -end\ -local casts = {\ - code_cast('javascript'),\ - code_cast('moonscript'),\ - code_cast('lua'),\ - code_cast('markdown'),\ - code_cast('html'),\ - {\ - inp = 'text/plain',\ - out = 'mmm/dom',\ - transform = function(val)\ - return text(val)\ - end\ - },\ - {\ - inp = 'URL.*',\ - out = 'mmm/dom',\ - transform = function(href)\ - return span(a((code(href)), {\ - href = href\ - }))\ - end\ - }\ -}\ -for _index_0 = 1, #converts do\ - local convert = converts[_index_0]\ - table.insert(casts, convert)\ -end\ -local Browser\ -do\ - local _class_0\ - local err_and_trace, default_convert\ - local _base_0 = {\ - get_content = function(self, prop, err, convert)\ - if err == nil then\ - err = self.error\ - end\ - if convert == nil then\ - convert = default_convert\ - end\ - local clear_error\ - clear_error = function()\ - if MODE == 'CLIENT' then\ - return err:set()\ - end\ - end\ - local disp_error\ - disp_error = function(msg)\ - if MODE == 'CLIENT' then\ - err:set(pre(msg))\ - end\ - warn(\"ERROR rendering content: \" .. tostring(msg))\ - return nil\ - end\ - local active = self.active:get()\ - if not (active) then\ - return disp_error(\"fileder not found!\")\ - end\ - if not (prop) then\ - return disp_error(\"facet not found!\")\ - end\ - local ok, res = xpcall(convert, err_and_trace, active, prop)\ - if MODE == 'CLIENT' then\ - document.body.classList:remove('loading')\ - end\ - if ok and res then\ - clear_error()\ - return res\ - elseif ok then\ - return div(\"[no conversion path to \" .. tostring(prop.type) .. \"]\")\ - elseif res and res.msg.match and res.msg:match('%[nossr%]$') then\ - return div(\"[this page could not be pre-rendered on the server]\")\ - else\ - res = tostring(res.msg) .. \"\\n\" .. tostring(res.trace)\ - return disp_error(res)\ - end\ - end,\ - get_inspector = function(self)\ - self.inspect_prop = self.facet:map(function(prop)\ - local active = self.active:get()\ - local key = active and active:find(prop)\ - if key and key.original then\ - key = key.original\ - end\ - return key\ - end)\ - self.inspect_err = ReactiveVar()\ - do\ - local _with_0 = div({\ - class = 'view inspector'\ - })\ - _with_0:append(nav({\ - span('inspector'),\ - self.inspect_prop:map(function(current)\ - current = current and current:tostring()\ - local fileder = self.active:get()\ - local onchange\ - onchange = function(_, e)\ - if e.target.value == '' then\ - return \ - end\ - local name\ - name = self.facet:get().name\ - return self.inspect_prop:set(Key(e.target.value))\ - end\ - do\ - local _with_1 = select({\ - onchange = onchange\ - })\ - _with_1:append(option('(none)', {\ - value = '',\ - disabled = true,\ - selected = not value\ - }))\ - if fileder then\ - for key, _ in pairs(fileder.facets) do\ - local value = key:tostring()\ - _with_1:append(option(value, {\ - value = value,\ - selected = value == current\ - }))\ - end\ - end\ - return _with_1\ - end\ - end),\ - self.inspect:map(function(enabled)\ - if enabled then\ - return button('close', {\ - onclick = function(_, e)\ - return self.inspect:set(false)\ - end\ - })\ - end\ - end)\ - }))\ - _with_0:append((function()\ - do\ - local _with_1 = div({\ - class = self.inspect_err:map(function(e)\ - if e then\ - return 'error-wrap'\ - else\ - return 'error-wrap empty'\ - end\ - end)\ - })\ - _with_1:append(span(\"an error occured while rendering this view:\"))\ - _with_1:append(self.inspect_err)\ - return _with_1\ - end\ - end)())\ - _with_0:append((function()\ - do\ - local _with_1 = pre({\ - class = 'content'\ - })\ - _with_1:append(keep(self.inspect_prop:map(function(prop, old)\ - return self:get_content(prop, self.inspect_err, function(self, prop)\ - local value, key = self:get(prop)\ - assert(key, \"couldn't @get \" .. tostring(prop))\ - local conversions = get_conversions('mmm/dom', key.type, casts)\ - assert(conversions, \"cannot cast '\" .. tostring(key.type) .. \"'\")\ - return apply_conversions(conversions, value, self, prop)\ - end)\ - end)))\ - return _with_1\ - end\ - end)())\ - return _with_0\ - end\ - end,\ - navigate = function(self, new)\ - return self.path:set(new)\ - end\ - }\ - _base_0.__index = _base_0\ - _class_0 = setmetatable({\ - __init = function(self, root, path, rehydrate)\ - if rehydrate == nil then\ - rehydrate = false\ - end\ - self.root = root\ - assert(self.root, 'root fileder is nil')\ - self.path = ReactiveVar(path or '')\ - if MODE == 'CLIENT' then\ - local logo = document:querySelector('header h1 > svg')\ - local spin\ - spin = function()\ - logo.classList:add('spin')\ - local _ = logo.parentElement.offsetWidth\ - return logo.classList:remove('spin')\ - end\ - self.path:subscribe(function(path)\ - document.body.classList:add('loading')\ - spin()\ - if self.skip then\ - return \ - end\ - local vis_path = path .. ((function()\ - if '/' == path:sub(-1) then\ - return ''\ - else\ - return '/'\ - end\ - end)())\ - return window.history:pushState(path, '', vis_path)\ - end)\ - window.onpopstate = function(_, event)\ - if event.state and not event.state == js.null then\ - self.skip = true\ - self.path:set(event.state)\ - self.skip = nil\ - end\ - end\ - end\ - self.active = self.path:map((function()\ - local _base_1 = self.root\ - local _fn_0 = _base_1.walk\ - return function(...)\ - return _fn_0(_base_1, ...)\ - end\ - end)())\ - self.facet = self.active:map(function(fileder)\ - if not (fileder) then\ - return \ - end\ - local last = self.facet and self.facet:get()\ - return Key((function()\ - if last then\ - return last.type\ - else\ - return 'mmm/dom'\ - end\ - end)())\ - end)\ - self.inspect = ReactiveVar((MODE == 'CLIENT' and window.location.search:match('[?&]inspect')))\ - local main = get_or_create('div', 'browser-root', {\ - class = 'main view'\ - })\ - if MODE == 'SERVER' then\ - main:append(nav({\ - id = 'browser-navbar',\ - span('please stand by... interactivity loading :)')\ - }))\ - else\ - main:prepend((function()\ - do\ - local _with_0 = get_or_create('nav', 'browser-navbar')\ - _with_0.node.innerHTML = ''\ - _with_0:append(span('path: ', self.path:map(function(path)\ - do\ - local _with_1 = div({\ - class = 'path',\ - style = {\ - display = 'inline-block'\ - }\ - })\ - local path_segment\ - path_segment = function(name, href)\ - return a(name, {\ - href = href,\ - onclick = function(_, e)\ - e:preventDefault()\ - return self:navigate(href)\ - end\ - })\ - end\ - local href = ''\ - path = path:match('^/(.*)')\ - _with_1:append(path_segment('root', ''))\ - while path do\ - local name, rest = path:match('^([%w%-_%.]+)/(.*)')\ - if not name then\ - name = path\ - end\ - path = rest\ - href = tostring(href) .. \"/\" .. tostring(name)\ - _with_1:append('/')\ - _with_1:append(path_segment(name, href))\ - end\ - return _with_1\ - end\ - end)))\ - _with_0:append(span('view facet:', {\ - style = {\ - ['margin-right'] = '0'\ - }\ - }))\ - _with_0:append(self.active:map(function(fileder)\ - local onchange\ - onchange = function(_, e)\ - local type\ - type = self.facet:get().type\ - return self.facet:set(Key({\ - name = e.target.value,\ - type = type\ - }))\ - end\ - local current = self.facet:get()\ - current = current and current.name\ - do\ - local _with_1 = select({\ - onchange = onchange,\ - disabled = not fileder\ - })\ - local has_main = fileder and fileder:find(current.name, '.*')\ - _with_1:append(option('(main)', {\ - value = '',\ - disabled = not has_main,\ - selected = current == ''\ - }))\ - if fileder then\ - for i, value in ipairs(fileder:get_facets()) do\ - local _continue_0 = false\ - repeat\ - if value == '' then\ - _continue_0 = true\ - break\ - end\ - _with_1:append(option(value, {\ - value = value,\ - selected = value == current\ - }))\ - _continue_0 = true\ - until true\ - if not _continue_0 then\ - break\ - end\ - end\ - end\ - return _with_1\ - end\ - end))\ - _with_0:append(self.inspect:map(function(enabled)\ - if not enabled then\ - return button('inspect', {\ - onclick = function(_, e)\ - return self.inspect:set(true)\ - end\ - })\ - end\ - end))\ - return _with_0\ - end\ - end)())\ - end\ - self.error = ReactiveVar()\ - main:append((function()\ - do\ - local _with_0 = get_or_create('div', 'browser-error', {\ - class = self.error:map(function(e)\ - if e then\ - return 'error-wrap'\ - else\ - return 'error-wrap empty'\ - end\ - end)\ - })\ - _with_0:append((span(\"an error occured while rendering this view:\")), (rehydrate and _with_0.node.firstChild))\ - _with_0:append(self.error)\ - return _with_0\ - end\ - end)())\ - main:append((function()\ - do\ - local _with_0 = get_or_create('div', 'browser-content', {\ - class = 'content'\ - })\ - local content = ReactiveVar((function()\ - if rehydrate then\ - return _with_0.node.lastChild\ - else\ - return self:get_content(self.facet:get())\ - end\ - end)())\ - _with_0:append(keep(content))\ - if MODE == 'CLIENT' then\ - self.facet:subscribe(function(p)\ - return window:setTimeout((function()\ - return content:set(self:get_content(p))\ - end), 150)\ - end)\ - end\ - return _with_0\ - end\ - end)())\ - if rehydrate then\ - self.facet:set(self.facet:get())\ - end\ - local inspector = self.inspect:map(function(enabled)\ - if enabled then\ - return self:get_inspector()\ - end\ - end)\ - local wrapper = get_or_create('div', 'browser-wrapper', main, inspector, {\ - class = 'browser'\ - })\ - self.node = wrapper.node\ - do\ - local _base_1 = wrapper\ - local _fn_0 = _base_1.render\ - self.render = function(...)\ - return _fn_0(_base_1, ...)\ - end\ - end\ - end,\ - __base = _base_0,\ - __name = \"Browser\"\ - }, {\ - __index = _base_0,\ - __call = function(cls, ...)\ - local _self_0 = setmetatable({}, _base_0)\ - cls.__init(_self_0, ...)\ - return _self_0\ - end\ - })\ - _base_0.__class = _class_0\ - local self = _class_0\ - err_and_trace = function(msg)\ - return {\ - msg = msg,\ - trace = debug.traceback()\ - }\ - end\ - default_convert = function(self, key)\ - return self:get(key.name, 'mmm/dom')\ - end\ - default_convert = function(self, key)\ - return self:get(key.name, 'mmm/dom')\ - end\ - Browser = _class_0\ -end\ -return {\ - Browser = Browser\ -}\ -", "mmm/mmmfs/browser.lua") end -if not p["mmm.mmmfs.conversion"] then p["mmm.mmmfs.conversion"] = load("local require = relative(..., 1)\ -local converts = require('.converts')\ -local count\ -count = function(base, pattern)\ - if pattern == nil then\ - pattern = '->'\ - end\ - return select(2, base:gsub(pattern, ''))\ -end\ -local escape_pattern\ -escape_pattern = function(inp)\ - return \"^\" .. tostring(inp:gsub('([^%w])', '%%%1')) .. \"$\"\ -end\ -local escape_inp\ -escape_inp = function(inp)\ - return \"^\" .. tostring(inp:gsub('([-/])', '%%%1')) .. \"$\"\ -end\ -local get_conversions\ -get_conversions = function(want, have, _converts, limit)\ - if _converts == nil then\ - _converts = converts\ - end\ - if limit == nil then\ - limit = 5\ - end\ - assert(have, 'need starting type(s)')\ - if 'string' == type(have) then\ - have = {\ - have\ - }\ - end\ - assert(#have > 0, 'need starting type(s) (list was empty)')\ - want = escape_pattern(want)\ - local iterations = limit + math.max(table.unpack((function()\ - local _accum_0 = { }\ - local _len_0 = 1\ - for _index_0 = 1, #have do\ - local type = have[_index_0]\ - _accum_0[_len_0] = count(type)\ - _len_0 = _len_0 + 1\ - end\ - return _accum_0\ - end)()))\ - do\ - local _accum_0 = { }\ - local _len_0 = 1\ - for _index_0 = 1, #have do\ - local start = have[_index_0]\ - _accum_0[_len_0] = {\ - start = start,\ - rest = start,\ - conversions = { }\ - }\ - _len_0 = _len_0 + 1\ - end\ - have = _accum_0\ - end\ - for i = 1, iterations do\ - local next_have, c = { }, 1\ - for _index_0 = 1, #have do\ - local _des_0 = have[_index_0]\ - local start, rest, conversions\ - start, rest, conversions = _des_0.start, _des_0.rest, _des_0.conversions\ - if rest:match(want) then\ - return conversions, start\ - else\ - for _index_1 = 1, #_converts do\ - local _continue_0 = false\ - repeat\ - local convert = _converts[_index_1]\ - local inp = escape_inp(convert.inp)\ - if not (rest:match(inp)) then\ - _continue_0 = true\ - break\ - end\ - local result = rest:gsub(inp, convert.out)\ - if result then\ - next_have[c] = {\ - start = start,\ - rest = result,\ - conversions = {\ - {\ - convert = convert,\ - from = rest,\ - to = result\ - },\ - table.unpack(conversions)\ - }\ - }\ - c = c + 1\ - end\ - _continue_0 = true\ - until true\ - if not _continue_0 then\ - break\ - end\ - end\ - end\ - end\ - have = next_have\ - if not (#have > 0) then\ - return \ - end\ - end\ -end\ -local apply_conversions\ -apply_conversions = function(conversions, value, ...)\ - for i = #conversions, 1, -1 do\ - local step = conversions[i]\ - value = step.convert.transform(step, value, ...)\ - end\ - return value\ -end\ -return {\ - converts = converts,\ - get_conversions = get_conversions,\ - apply_conversions = apply_conversions\ -}\ -", "mmm/mmmfs/conversion.lua") end -if not p["mmm.mmmfs.fileder"] then p["mmm.mmmfs.fileder"] = load("local require = relative(..., 1)\ -local get_conversions, apply_conversions\ -do\ - local _obj_0 = require('.conversion')\ - get_conversions, apply_conversions = _obj_0.get_conversions, _obj_0.apply_conversions\ -end\ -local Key\ -do\ - local _class_0\ - local _base_0 = {\ - tostring = function(self)\ - if self.name == '' then\ - return self.type\ - else\ - return tostring(self.name) .. \": \" .. tostring(self.type)\ - end\ - end,\ - __tostring = function(self)\ - return self:tostring()\ - end\ - }\ - _base_0.__index = _base_0\ - _class_0 = setmetatable({\ - __init = function(self, opts, second)\ - if 'string' == type(second) then\ - self.name, self.type = (opts or ''), second\ - elseif 'string' == type(opts) then\ - self.name, self.type = opts:match('^([%w-_]+): *(.+)$')\ - if not self.name then\ - self.name = ''\ - self.type = opts\ - end\ - elseif 'table' == type(opts) then\ - self.name = opts.name\ - self.type = opts.type\ - self.original = opts.original\ - self.filename = opts.filename\ - else\ - return error(\"wrong argument type: \" .. tostring(type(opts)) .. \", \" .. tostring(type(second)))\ - end\ - end,\ - __base = _base_0,\ - __name = \"Key\"\ - }, {\ - __index = _base_0,\ - __call = function(cls, ...)\ - local _self_0 = setmetatable({}, _base_0)\ - cls.__init(_self_0, ...)\ - return _self_0\ - end\ - })\ - _base_0.__class = _class_0\ - Key = _class_0\ -end\ -local Fileder\ -do\ - local _class_0\ - local _base_0 = {\ - walk = function(self, path)\ - if path == '' then\ - return self\ - end\ - if '/' ~= path:sub(1, 1) then\ - path = tostring(self.path) .. \"/\" .. tostring(path)\ - end\ - if not (self.path == path:sub(1, #self.path)) then\ - return \ - end\ - if #path == #self.path then\ - return self\ - end\ - local _list_0 = self.children\ - for _index_0 = 1, #_list_0 do\ - local child = _list_0[_index_0]\ - do\ - local match = child:walk(path)\ - if match then\ - return match\ - end\ - end\ - end\ - end,\ - mount = function(self, path, mount_as)\ - if not mount_as then\ - path = path .. self:gett('name: alpha')\ - end\ - assert(not self.path or self.path == path, \"mounted twice: \" .. tostring(self.path) .. \" and now \" .. tostring(path))\ - self.path = path\ - local _list_0 = self.children\ - for _index_0 = 1, #_list_0 do\ - local child = _list_0[_index_0]\ - child:mount(self.path .. '/')\ - end\ - end,\ - iterate = function(self, depth)\ - if depth == nil then\ - depth = 0\ - end\ - coroutine.yield(self)\ - if depth == 1 then\ - return \ - end\ - local _list_0 = self.children\ - for _index_0 = 1, #_list_0 do\ - local child = _list_0[_index_0]\ - child:iterate(depth - 1)\ - end\ - end,\ - get_facets = function(self)\ - local names = { }\ - for key in pairs(self.facets) do\ - names[key.name] = true\ - end\ - local _accum_0 = { }\ - local _len_0 = 1\ - for name in pairs(names) do\ - _accum_0[_len_0] = name\ - _len_0 = _len_0 + 1\ - end\ - return _accum_0\ - end,\ - has = function(self, ...)\ - local want = Key(...)\ - for key in pairs(self.facets) do\ - local _continue_0 = false\ - repeat\ - if key.original then\ - _continue_0 = true\ - break\ - end\ - if key.name == want.name and key.type == want.type then\ - return key\ - end\ - _continue_0 = true\ - until true\ - if not _continue_0 then\ - break\ - end\ - end\ - end,\ - has_facet = function(self, want)\ - for key in pairs(self.facets) do\ - local _continue_0 = false\ - repeat\ - if key.original then\ - _continue_0 = true\ - break\ - end\ - if key.name == want then\ - return key\ - end\ - _continue_0 = true\ - until true\ - if not _continue_0 then\ - break\ - end\ - end\ - end,\ - find = function(self, ...)\ - local want = Key(...)\ - local matching\ - do\ - local _accum_0 = { }\ - local _len_0 = 1\ - for key in pairs(self.facets) do\ - if key.name == want.name then\ - _accum_0[_len_0] = key\ - _len_0 = _len_0 + 1\ - end\ - end\ - matching = _accum_0\ - end\ - if not (#matching > 0) then\ - return \ - end\ - local shortest_path, start = get_conversions(want.type, (function()\ - local _accum_0 = { }\ - local _len_0 = 1\ - for _index_0 = 1, #matching do\ - local key = matching[_index_0]\ - _accum_0[_len_0] = key.type\ - _len_0 = _len_0 + 1\ - end\ - return _accum_0\ - end)())\ - if start then\ - for _index_0 = 1, #matching do\ - local key = matching[_index_0]\ - if key.type == start then\ - return key, shortest_path\ - end\ - end\ - return error(\"couldn't find key after resolution?\")\ - end\ - end,\ - get = function(self, ...)\ - local want = Key(...)\ - local key, conversions = self:find(want)\ - if key then\ - local value = apply_conversions(conversions, self.facets[key], self, key)\ - return value, key\ - end\ - end,\ - gett = function(self, ...)\ - local want = Key(...)\ - local value, key = self:get(want)\ - assert(value, tostring(self) .. \" doesn't have value for '\" .. tostring(want) .. \"'\")\ - return value, key\ - end,\ - __tostring = function(self)\ - return \"Fileder:\" .. tostring(self.path)\ - end\ - }\ - _base_0.__index = _base_0\ - _class_0 = setmetatable({\ - __init = function(self, facets, children)\ - if not children then\ - do\ - local _accum_0 = { }\ - local _len_0 = 1\ - for i, child in ipairs(facets) do\ - facets[i] = nil\ - local _value_0 = child\ - _accum_0[_len_0] = _value_0\ - _len_0 = _len_0 + 1\ - end\ - children = _accum_0\ - end\ - end\ - self.children = setmetatable({ }, {\ - __index = function(t, k)\ - if not ('string' == type(k)) then\ - return rawget(t, k)\ - end\ - return self:walk(tostring(self.path) .. \"/\" .. tostring(k))\ - end,\ - __newindex = function(t, k, child)\ - rawset(t, k, child)\ - if self.path == '/' then\ - return child:mount('/')\ - elseif self.path then\ - return child:mount(self.path .. '/')\ - end\ - end\ - })\ - for i, child in ipairs(children) do\ - self.children[i] = child\ - end\ - self.facets = setmetatable({ }, {\ - __newindex = function(t, key, v)\ - return rawset(t, (Key(key)), v)\ - end\ - })\ - for k, v in pairs(facets) do\ - self.facets[k] = v\ - end\ - end,\ - __base = _base_0,\ - __name = \"Fileder\"\ - }, {\ - __index = _base_0,\ - __call = function(cls, ...)\ - local _self_0 = setmetatable({}, _base_0)\ - cls.__init(_self_0, ...)\ - return _self_0\ - end\ - })\ - _base_0.__class = _class_0\ - Fileder = _class_0\ -end\ -local dir_base\ -dir_base = function(path)\ - local dir, base = path:match('(.-)([^/]-)$')\ - if dir and #dir > 0 then\ - dir = dir:sub(1, #dir - 1)\ - end\ - return dir, base\ -end\ -local load_tree\ -load_tree = function(store, root)\ - if root == nil then\ - root = ''\ - end\ - local fileders = setmetatable({ }, {\ - __index = function(self, path)\ - do\ - local val = Fileder({ })\ - val.path = path\ - rawset(self, path, val)\ - return val\ - end\ - end\ - })\ - root = fileders[root]\ - root.facets['name: alpha'] = ''\ - for fn, ft in store:list_facets(root.path) do\ - local val = store:load_facet(root.path, fn, ft)\ - root.facets[Key(fn, ft)] = val\ - end\ - for path in store:list_all_fileders(root.path) do\ - local fileder = fileders[path]\ - local parent, name = dir_base(path)\ - fileder.facets['name: alpha'] = name\ - table.insert(fileders[parent].children, fileder)\ - for fn, ft in store:list_facets(path) do\ - local val = store:load_facet(path, fn, ft)\ - fileder.facets[Key(fn, ft)] = val\ - end\ - end\ - return root\ -end\ -return {\ - Key = Key,\ - Fileder = Fileder,\ - dir_base = dir_base,\ - load_tree = load_tree\ -}\ -", "mmm/mmmfs/fileder.lua") end -if not p["mmm.mmmfs"] then p["mmm.mmmfs"] = load("local require = relative(...)\ -local Key, Fileder\ -do\ - local _obj_0 = require('.fileder')\ - Key, Fileder = _obj_0.Key, _obj_0.Fileder\ -end\ -local Browser\ -Browser = require('.browser').Browser\ -return {\ - Key = Key,\ - Fileder = Fileder,\ - Browser = Browser\ -}\ -", "mmm/mmmfs/init.lua") end -if not p["mmm.mmmfs.util"] then p["mmm.mmmfs.util"] = load("local merge\ -merge = function(orig, extra)\ - if orig == nil then\ - orig = { }\ - end\ - do\ - local attr\ - do\ - local _tbl_0 = { }\ - for k, v in pairs(orig) do\ - _tbl_0[k] = v\ - end\ - attr = _tbl_0\ - end\ - for k, v in pairs(extra) do\ - attr[k] = v\ - end\ - return attr\ - end\ -end\ -local tourl\ -tourl = function(path)\ - if STATIC then\ - return path .. '/'\ - else\ - return path .. '/'\ - end\ -end\ -return function(elements)\ - local a, div, pre\ - a, div, pre = elements.a, elements.div, elements.pre\ - local find_fileder\ - find_fileder = function(fileder, origin)\ - if 'string' == type(fileder) then\ - assert(origin, \"cannot resolve path '\" .. tostring(fileder) .. \"' without origin!\")\ - return assert((origin:walk(fileder)), \"couldn't resolve path '\" .. tostring(fileder) .. \"' from \" .. tostring(origin))\ - else\ - return assert(fileder, \"no fileder passed.\")\ - end\ - end\ - local navigate_to\ - navigate_to = function(path, name, opts)\ - if opts == nil then\ - opts = { }\ - end\ - opts.href = tourl(path)\ - if MODE == 'CLIENT' then\ - opts.onclick = function(self, e)\ - e:preventDefault()\ - return BROWSER:navigate(path)\ - end\ - end\ - return a(name, opts)\ - end\ - local link_to\ - link_to = function(fileder, name, origin, attr)\ - fileder = find_fileder(fileder, origin)\ - name = name or fileder:get('title: mmm/dom')\ - name = name or fileder:gett('name: alpha')\ - do\ - local href = fileder:get('link: URL.*')\ - if href then\ - return a(name, merge(attr, {\ - href = href,\ - target = '_blank'\ - }))\ - else\ - return a(name, merge(attr, {\ - href = tourl(fileder.path),\ - onclick = (function()\ - if MODE == 'CLIENT' then\ - return function(self, e)\ - e:preventDefault()\ - return BROWSER:navigate(fileder.path)\ - end\ - end\ - end)()\ - }))\ - end\ - end\ - end\ - local embed\ - embed = function(fileder, name, origin, opts)\ - if name == nil then\ - name = ''\ - end\ - if opts == nil then\ - opts = { }\ - end\ - fileder = find_fileder(fileder, origin)\ - local ok, node = pcall(fileder.gett, fileder, name, 'mmm/dom')\ - if not ok then\ - return div(\"couldn't embed \" .. tostring(fileder) .. \" \" .. tostring(name), (pre(node)), {\ - style = {\ - background = 'var(--gray-fail)',\ - padding = '1em'\ - }\ - })\ - end\ - local klass = 'embed'\ - if opts.desc then\ - klass = klass .. ' desc'\ - end\ - if opts.inline then\ - klass = klass .. ' inline'\ - end\ - node = div({\ - class = klass,\ - node,\ - (function()\ - if opts.desc then\ - return div(opts.desc, {\ - class = 'description'\ - })\ - end\ - end)()\ - })\ - if opts.nolink then\ - return node\ - end\ - return link_to(fileder, node, nil, opts.attr)\ - end\ - return {\ - find_fileder = find_fileder,\ - link_to = link_to,\ - navigate_to = navigate_to,\ - embed = embed\ - }\ -end\ -", "mmm/mmmfs/util.lua") end -if not p["mmm.mmmfs.converts"] then p["mmm.mmmfs.converts"] = load("local require = relative(..., 1)\ -local div, code, img, video, blockquote, a, span, source, iframe\ -do\ - local _obj_0 = require('mmm.dom')\ - div, code, img, video, blockquote, a, span, source, iframe = _obj_0.div, _obj_0.code, _obj_0.img, _obj_0.video, _obj_0.blockquote, _obj_0.a, _obj_0.span, _obj_0.source, _obj_0.iframe\ -end\ -local find_fileder, link_to, embed\ -do\ - local _obj_0 = (require('mmm.mmmfs.util'))(require('mmm.dom'))\ - find_fileder, link_to, embed = _obj_0.find_fileder, _obj_0.link_to, _obj_0.embed\ -end\ -local render\ -render = require('.layout').render\ -local tohtml\ -tohtml = require('mmm.component').tohtml\ -local js_fix\ -if MODE == 'CLIENT' then\ - js_fix = function(arg)\ - if arg == js.null then\ - return \ - end\ - return arg\ - end\ -end\ -local single\ -single = function(func)\ - return function(self, val)\ - return func(val)\ - end\ -end\ -local loadwith\ -loadwith = function(_load)\ - return function(self, val, fileder, key)\ - local func = assert(_load(val, tostring(fileder) .. \"#\" .. tostring(key)))\ - return func()\ - end\ -end\ -local converts = {\ - {\ - inp = 'fn -> (.+)',\ - out = '%1',\ - transform = function(self, val, fileder)\ - return val(fileder)\ - end\ - },\ - {\ - inp = 'mmm/component',\ - out = 'mmm/dom',\ - transform = single(tohtml)\ - },\ - {\ - inp = 'mmm/dom',\ - out = 'text/html+frag',\ - transform = function(self, node)\ - if MODE == 'SERVER' then\ - return node\ - else\ - return node.outerHTML\ - end\ - end\ - },\ - {\ - inp = 'mmm/dom',\ - out = 'text/html',\ - transform = function(self, html, fileder)\ - return render(html, fileder)\ - end\ - },\ - {\ - inp = 'text/html%+frag',\ - out = 'mmm/dom',\ - transform = (function()\ - if MODE == 'SERVER' then\ - return function(self, html, fileder)\ - html = html:gsub('(.-)', function(attrs, text)\ - if #text == 0 then\ - text = nil\ - end\ - local path = ''\ - while attrs and attrs ~= '' do\ - local key, val, _attrs = attrs:match('^(%w+)=\"([^\"]-)\"%s*(.*)')\ - if not key then\ - key, _attrs = attrs:match('^(%w+)%s*(.*)$')\ - val = true\ - end\ - attrs = _attrs\ - local _exp_0 = key\ - if 'path' == _exp_0 then\ - path = val\ - else\ - warn(\"unkown attribute '\" .. tostring(key) .. \"=\\\"\" .. tostring(val) .. \"\\\"' in \")\ - end\ - end\ - return link_to(path, text, fileder)\ - end)\ - html = html:gsub('(.-)', function(attrs, desc)\ - local path, facet = '', ''\ - local opts = { }\ - if #desc ~= 0 then\ - opts.desc = desc\ - end\ - while attrs and attrs ~= '' do\ - local key, val, _attrs = attrs:match('^(%w+)=\"([^\"]-)\"%s*(.*)')\ - if not key then\ - key, _attrs = attrs:match('^(%w+)%s*(.*)$')\ - val = true\ - end\ - attrs = _attrs\ - local _exp_0 = key\ - if 'path' == _exp_0 then\ - path = val\ - elseif 'facet' == _exp_0 then\ - facet = val\ - elseif 'nolink' == _exp_0 then\ - opts.nolink = true\ - elseif 'inline' == _exp_0 then\ - opts.inline = true\ - else\ - warn(\"unkown attribute '\" .. tostring(key) .. \"=\\\"\" .. tostring(val) .. \"\\\"' in \")\ - end\ - end\ - return embed(path, facet, fileder, opts)\ - end)\ - return html\ - end\ - else\ - return function(self, html, fileder)\ - local parent\ - do\ - local _with_0 = document:createElement('div')\ - _with_0.innerHTML = html\ - local embeds = _with_0:getElementsByTagName('mmm-embed')\ - do\ - local _accum_0 = { }\ - local _len_0 = 1\ - for i = 0, embeds.length - 1 do\ - _accum_0[_len_0] = embeds[i]\ - _len_0 = _len_0 + 1\ - end\ - embeds = _accum_0\ - end\ - for _index_0 = 1, #embeds do\ - local element = embeds[_index_0]\ - local path = js_fix(element:getAttribute('path'))\ - local facet = js_fix(element:getAttribute('facet'))\ - local nolink = js_fix(element:getAttribute('nolink'))\ - local inline = js_fix(element:getAttribute('inline'))\ - local desc = js_fix(element.innerText)\ - element:replaceWith(embed(path or '', facet or '', fileder, {\ - nolink = nolink,\ - inline = inline,\ - desc = desc\ - }))\ - end\ - embeds = _with_0:getElementsByTagName('mmm-link')\ - do\ - local _accum_0 = { }\ - local _len_0 = 1\ - for i = 0, embeds.length - 1 do\ - _accum_0[_len_0] = embeds[i]\ - _len_0 = _len_0 + 1\ - end\ - embeds = _accum_0\ - end\ - for _index_0 = 1, #embeds do\ - local element = embeds[_index_0]\ - local text = js_fix(element.innerText)\ - local path = js_fix(element:getAttribute('path'))\ - element:replaceWith(link_to(path or '', text, fileder))\ - end\ - parent = _with_0\ - end\ - assert(1 == parent.childElementCount, \"text/html with more than one child!\")\ - return parent.firstElementChild\ - end\ - end\ - end)()\ - },\ - {\ - inp = 'text/lua -> (.+)',\ - out = '%1',\ - transform = loadwith(load or loadstring)\ - },\ - {\ - inp = 'mmm/tpl -> (.+)',\ - out = '%1',\ - transform = function(self, source, fileder)\ - return source:gsub('{{(.-)}}', function(expr)\ - local path, facet = expr:match('^([%w%-_%./]*)%+(.*)')\ - assert(path, \"couldn't match TPL expression '\" .. tostring(expr) .. \"'\")\ - return (find_fileder(path, fileder)):gett(facet)\ - end)\ - end\ - },\ - {\ - inp = 'time/iso8601-date',\ - out = 'time/unix',\ - transform = function(self, val)\ - local year, _, month, day = val:match('^%s*(%d%d%d%d)(%-?)([01]%d)%2([0-3]%d)%s*$')\ - assert(year, \"failed to parse ISO 8601 date: '\" .. tostring(val) .. \"'\")\ - return os.time({\ - year = year,\ - month = month,\ - day = day\ - })\ - end\ - },\ - {\ - inp = 'URL -> twitter/tweet',\ - out = 'mmm/dom',\ - transform = function(self, href)\ - local id = assert((href:match('twitter.com/[^/]-/status/(%d*)')), \"couldn't parse twitter/tweet URL: '\" .. tostring(href) .. \"'\")\ - if MODE == 'CLIENT' then\ - do\ - local parent = div()\ - window.twttr.widgets:createTweet(id, parent)\ - return parent\ - end\ - else\ - return div(blockquote({\ - class = 'twitter-tweet',\ - ['data-lang'] = 'en',\ - a('(linked tweet)', {\ - href = href\ - })\ - }))\ - end\ - end\ - },\ - {\ - inp = 'URL -> youtube/video',\ - out = 'mmm/dom',\ - transform = function(self, link)\ - local id = link:match('youtu%.be/([^/]+)')\ - id = id or link:match('youtube.com/watch.*[?&]v=([^&]+)')\ - id = id or link:match('youtube.com/[ev]/([^/]+)')\ - id = id or link:match('youtube.com/embed/([^/]+)')\ - assert(id, \"couldn't parse youtube URL: '\" .. tostring(link) .. \"'\")\ - return iframe({\ - width = 560,\ - height = 315,\ - frameborder = 0,\ - allowfullscreen = true,\ - frameBorder = 0,\ - src = \"//www.youtube.com/embed/\" .. tostring(id)\ - })\ - end\ - },\ - {\ - inp = 'URL -> image/.+',\ - out = 'mmm/dom',\ - transform = function(self, src, fileder)\ - return img({\ - src = src\ - })\ - end\ - },\ - {\ - inp = 'URL -> video/.+',\ - out = 'mmm/dom',\ - transform = function(self, src)\ - return video((source({\ - src = src\ - })), {\ - controls = true,\ - loop = true\ - })\ - end\ - },\ - {\ - inp = 'text/plain',\ - out = 'mmm/dom',\ - transform = function(self, val)\ - return span(val)\ - end\ - },\ - {\ - inp = 'alpha',\ - out = 'mmm/dom',\ - transform = single(code)\ - },\ - {\ - inp = '(.+)',\ - out = 'URL -> %1',\ - transform = function(self, _, fileder, key)\ - return tostring(fileder.path) .. \"/\" .. tostring(key.name) .. \":\" .. tostring(self.from)\ - end\ - }\ -}\ -if MODE == 'SERVER' then\ - local ok, moon = pcall(require, 'moonscript.base')\ - if ok then\ - local _load = moon.load or moon.loadstring\ - table.insert(converts, {\ - inp = 'text/moonscript -> (.+)',\ - out = '%1',\ - transform = loadwith(moon.load or moon.loadstring)\ - })\ - table.insert(converts, {\ - inp = 'text/moonscript -> (.+)',\ - out = 'text/lua -> %1',\ - transform = single(moon.to_lua)\ - })\ - end\ -else\ - table.insert(converts, {\ - inp = 'text/javascript -> (.+)',\ - out = '%1',\ - transform = function(self, source)\ - local f = js.new(window.Function, source)\ - return f()\ - end\ - })\ -end\ -do\ - local markdown\ - if MODE == 'SERVER' then\ - local success, discount = pcall(require, 'discount')\ - if not success then\ - warn(\"NO MARKDOWN SUPPORT!\", discount)\ - end\ - markdown = success and function(md)\ - local res = assert(discount.compile(md, 'githubtags'))\ - return res.body\ - end\ - else\ - markdown = window and window.marked and (function()\ - local _base_0 = window\ - local _fn_0 = _base_0.marked\ - return function(...)\ - return _fn_0(_base_0, ...)\ - end\ - end)()\ - end\ - if markdown then\ - table.insert(converts, {\ - inp = 'text/markdown',\ - out = 'text/html+frag',\ - transform = function(self, md)\ - return \"
\" .. tostring(markdown(md)) .. \"
\"\ - end\ - })\ - table.insert(converts, {\ - inp = 'text/markdown%+span',\ - out = 'mmm/dom',\ - transform = (function()\ - if MODE == 'SERVER' then\ - return function(self, source)\ - local html = markdown(source)\ - html = html:gsub('^$', '/span>')\ - end\ - else\ - return function(self, source)\ - local html = markdown(source)\ - html = html:gsub('^%s*

%s*', '')\ - html = html:gsub('%s*

%s*$', '')\ - do\ - local _with_0 = document:createElement('span')\ - _with_0.innerHTML = html\ - return _with_0\ - end\ - end\ - end\ - end)()\ - })\ - end\ -end\ -return converts\ -", "mmm/mmmfs/converts.lua") end -if not p["mmm.mmmfs.layout"] then p["mmm.mmmfs.layout"] = load("local require = relative(..., 1)\ -local header, aside, footer, div, svg, script, g, circle, h1, span, b, a, img\ -do\ - local _obj_0 = require('mmm.dom')\ - header, aside, footer, div, svg, script, g, circle, h1, span, b, a, img = _obj_0.header, _obj_0.aside, _obj_0.footer, _obj_0.div, _obj_0.svg, _obj_0.script, _obj_0.g, _obj_0.circle, _obj_0.h1, _obj_0.span, _obj_0.b, _obj_0.a, _obj_0.img\ -end\ -local navigate_to\ -navigate_to = (require('mmm.mmmfs.util'))(require('mmm.dom')).navigate_to\ -local pick\ -pick = function(...)\ - local num = select('#', ...)\ - local i = math.ceil(math.random() * num)\ - return (select(i, ...))\ -end\ -local iconlink\ -iconlink = function(href, src, alt, style)\ - return a({\ - class = 'iconlink',\ - target = '_blank',\ - rel = 'me',\ - href = href,\ - img({\ - src = src,\ - alt = alt,\ - style = style\ - })\ - })\ -end\ -local logo = svg({\ - class = 'sun',\ - viewBox = '-0.75 -1 1.5 2',\ - xmlns = 'http://www.w3.org/2000/svg',\ - baseProfile = 'full',\ - version = '1.1',\ - g({\ - transform = 'translate(0 .18)',\ - g({\ - class = 'circle out',\ - circle({\ - r = '.6',\ - fill = 'none',\ - ['stroke-width'] = '.12'\ - })\ - }),\ - g({\ - class = 'circle in',\ - circle({\ - r = '.2',\ - stroke = 'none'\ - })\ - })\ - })\ -})\ -local gen_header\ -gen_header = function()\ - return header({\ - div({\ - h1({\ - navigate_to('', logo),\ - span({\ - span('mmm', {\ - class = 'bold'\ - }),\ - '​',\ - '.s‑ol.nu'\ - })\ - }),\ - table.concat({\ - pick('fun', 'cool', 'weird', 'interesting', 'new', 'pleasant'),\ - pick('stuff', 'things', 'projects', 'experiments', 'visuals', 'ideas'),\ - pick(\"with\", 'and'),\ - pick('mostly code', 'code and wires', 'silicon', 'electronics', 'shaders', 'oscilloscopes', 'interfaces', 'hardware', 'FPGAs')\ - }, ' ')\ - }),\ - aside({\ - navigate_to('/about', 'about me'),\ - navigate_to('/games', 'games'),\ - navigate_to('/projects', 'other'),\ - a({\ - href = 'mailto:s%20[removethis]%20[at]%20s-ol.nu',\ - 'contact',\ - script(\"\\n var l = document.currentScript.parentElement;\\n l.href = l.href.replace('%20[at]%20', '@');\\n l.href = l.href.replace('%20[removethis]', '') + '?subject=Hey there :)';\\n \")\ - })\ - })\ - })\ -end\ -footer = footer({\ - span({\ - 'made with \\xe2\\x98\\xbd by ',\ - a('s-ol', {\ - href = 'https://twitter.com/S0lll0s'\ - }),\ - \", \" .. tostring(os.date('%Y'))\ - }),\ - div({\ - class = 'icons',\ - iconlink('https://github.com/s-ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/github.svg', 'github'),\ - iconlink('https://merveilles.town/@s_ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/mastodon.svg', 'mastodon'),\ - iconlink('https://twitter.com/S0lll0s', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/twitter.svg', 'twitter'),\ - iconlink('https://webring.xxiivv.com/#random', 'https://webring.xxiivv.com/icon.black.svg', 'webring', {\ - height = '1.3em',\ - ['margin-left'] = '.3em',\ - ['margin-top'] = '-0.12em'\ - })\ - })\ -})\ -local get_meta\ -get_meta = function(self)\ - local title = (self:get('title: text/plain')) or self:gett('name: alpha')\ - local l\ - l = function(str)\ - str = str:gsub('[%s\\\\n]+$', '')\ - return str:gsub('\\\\n', ' ')\ - end\ - local e\ - e = function(str)\ - return string.format('%q', l(str))\ - end\ - local meta = \"\\n \\n \" .. tostring(l(title)) .. \"\\n \"\ - do\ - local page_meta = self:get('_meta: mmm/dom')\ - if page_meta then\ - meta = meta .. page_meta\ - else\ - meta = meta .. \"\\n \\n\\n \\n \\n \\n \"\ - do\ - local desc = self:get('description: text/plain')\ - if desc then\ - meta = meta .. \"\\n \"\ - end\ - end\ - end\ - end\ - return meta\ -end\ -local render\ -render = function(content, fileder, opts)\ - if opts == nil then\ - opts = { }\ - end\ - opts.meta = opts.meta or get_meta(fileder)\ - opts.scripts = opts.scripts or ''\ - if not (opts.noview) then\ - content = [[
\ -
\ - ]] .. content .. [[
\ -
\ - ]]\ - end\ - local buf = [[\ -\ - \ - \ - \ - ]]\ - buf = buf .. \"\\n \" .. tostring(get_meta(fileder)) .. \"\\n \\n \\n \" .. tostring(gen_header()) .. \"\\n\\n \" .. tostring(content) .. \"\\n\\n \" .. tostring(footer) .. \"\\n \"\ - buf = buf .. [[ \ - \ - \ - \ - \ - \ - \ - ]]\ - buf = buf .. opts.scripts\ - buf = buf .. \"\\n \\n\\n \"\ - return buf\ -end\ -return {\ - render = render\ -}\ -", "mmm/mmmfs/layout.lua") end -if not p["mmm.mmmfs.stores.fs"] then p["mmm.mmmfs.stores.fs"] = load("local lfs = require('lfs')\ -local dir_base\ -dir_base = function(path)\ - local dir, base = path:match('(.-)([^/]-)$')\ - if dir and #dir > 0 then\ - dir = dir:sub(1, #dir - 1)\ - end\ - return dir, base\ -end\ -local FSStore\ -do\ - local _class_0\ - local _base_0 = {\ - log = function(self, ...)\ - return print(\"[DB]\", ...)\ - end,\ - list_fileders_in = function(self, path)\ - if path == nil then\ - path = ''\ - end\ - return coroutine.wrap(function()\ - for entry_name in lfs.dir(self.root .. path) do\ - local _continue_0 = false\ - repeat\ - if '.' == entry_name:sub(1, 1) then\ - _continue_0 = true\ - break\ - end\ - local entry_path = self.root .. tostring(path) .. \"/\" .. tostring(entry_name)\ - if 'directory' == lfs.attributes(entry_path, 'mode') then\ - coroutine.yield(tostring(path) .. \"/\" .. tostring(entry_name))\ - end\ - _continue_0 = true\ - until true\ - if not _continue_0 then\ - break\ - end\ - end\ - end)\ - end,\ - list_all_fileders = function(self, path)\ - if path == nil then\ - path = ''\ - end\ - return coroutine.wrap(function()\ - for path in self:list_fileders_in(path) do\ - coroutine.yield(path)\ - for p in self:list_all_fileders(path) do\ - coroutine.yield(p)\ - end\ - end\ - end)\ - end,\ - create_fileder = function(self, parent, name)\ - self:log(\"creating fileder \" .. tostring(path))\ - local path = tostring(parent) .. \"/\" .. tostring(name)\ - assert(lfs.mkdir(self.root .. path))\ - return path\ - end,\ - remove_fileder = function(self, path)\ - self:log(\"removing fileder \" .. tostring(path))\ - local rmdir\ - rmdir = function(path)\ - for file in lfs.dir(path) do\ - local _continue_0 = false\ - repeat\ - if '.' == file:sub(1, 1) then\ - _continue_0 = true\ - break\ - end\ - local file_path = tostring(path) .. \"/\" .. tostring(file)\ - local _exp_0 = lfs.attributes(file_path, 'mode')\ - if 'file' == _exp_0 then\ - assert(os.remove(file_path))\ - elseif 'directory' == _exp_0 then\ - assert(rmdir(file_path))\ - end\ - _continue_0 = true\ - until true\ - if not _continue_0 then\ - break\ - end\ - end\ - return lfs.rmdir(path)\ - end\ - return rmdir(self.root .. path)\ - end,\ - rename_fileder = function(self, path, next_name)\ - self:log(\"renaming fileder \" .. tostring(path) .. \" -> '\" .. tostring(next_name) .. \"'\")\ - local parent, name = dir_base(path)\ - return assert(os.rename(path, self.root .. tostring(parent) .. \"/\" .. tostring(next_name)))\ - end,\ - move_fileder = function(self, path, next_parent)\ - self:log(\"moving fileder \" .. tostring(path) .. \" -> \" .. tostring(next_parent) .. \"/\")\ - local parent, name = dir_base(path)\ - return assert(os.rename(self.root .. path, self.root .. tostring(next_parent) .. \"/\" .. tostring(name)))\ - end,\ - list_facets = function(self, path)\ - return coroutine.wrap(function()\ - for entry_name in lfs.dir(self.root .. path) do\ - local entry_path = tostring(self.root .. path) .. \"/\" .. tostring(entry_name)\ - if 'file' == lfs.attributes(entry_path, 'mode') then\ - entry_name = (entry_name:match('(.*)%.%w+')) or entry_name\ - entry_name = entry_name:gsub('%$', '/')\ - local name, type = entry_name:match('([%w-_]+): *(.+)')\ - if not name then\ - name = ''\ - type = entry_name\ - end\ - coroutine.yield(name, type)\ - end\ - end\ - end)\ - end,\ - tofp = function(self, path, name, type)\ - if #name > 0 then\ - type = tostring(name) .. \": \" .. tostring(type)\ - end\ - type = type:gsub('%/', '$')\ - return self.root .. tostring(path) .. \"/\" .. tostring(type)\ - end,\ - locate = function(self, path, name, type)\ - if not (lfs.attributes(self.root .. path, 'mode')) then\ - return \ - end\ - type = type:gsub('%/', '$')\ - if #name > 0 then\ - name = tostring(name) .. \": \"\ - end\ - name = name .. type\ - name = name:gsub('([^%w])', '%%%1')\ - local file_name\ - for entry_name in lfs.dir(self.root .. path) do\ - if (entry_name:match(\"^\" .. tostring(name) .. \"$\")) or entry_name:match(\"^\" .. tostring(name) .. \"%.%w+$\") then\ - if file_name then\ - error(\"two files match \" .. tostring(name) .. \": \" .. tostring(file_name) .. \" and \" .. tostring(entry_name) .. \"!\")\ - end\ - file_name = entry_name\ - end\ - end\ - return file_name and self.root .. tostring(path) .. \"/\" .. tostring(file_name)\ - end,\ - load_facet = function(self, path, name, type)\ - local filepath = self:locate(path, name, type)\ - if not (filepath) then\ - return \ - end\ - local file = assert((io.open(filepath, 'rb')), \"couldn't open facet file '\" .. tostring(filepath) .. \"'\")\ - do\ - local _with_0 = file:read('*all')\ - file:close()\ - return _with_0\ - end\ - end,\ - create_facet = function(self, path, name, type, blob)\ - self:log(\"creating facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\ - assert(blob, \"cant create facet without value!\")\ - local filepath = self:tofp(path, name, type)\ - if lfs.attributes(filepath, 'mode') then\ - error(\"facet file already exists!\")\ - end\ - local file = assert((io.open(filepath, 'wb')), \"couldn't open facet file '\" .. tostring(filepath) .. \"'\")\ - file:write(blob)\ - return file:close()\ - end,\ - remove_facet = function(self, path, name, type)\ - self:log(\"removing facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\ - local filepath = self:locate(path, name, type)\ - assert(filepath, \"couldn't locate facet!\")\ - return assert(os.remove(filepath))\ - end,\ - rename_facet = function(self, path, name, type, next_name)\ - self:log(\"renaming facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type) .. \" -> \" .. tostring(next_name))\ - local filepath = self:locate(path, name, type)\ - assert(filepath, \"couldn't locate facet!\")\ - return assert(os.rename(filepath, self:tofp(path, next_name, type)))\ - end,\ - update_facet = function(self, path, name, type, blob)\ - self:log(\"updating facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\ - local filepath = self:locate(path, name, type)\ - assert(filepath, \"couldn't locate facet!\")\ - local file = assert((io.open(filepath, 'wb')), \"couldn't open facet file '\" .. tostring(filepath) .. \"'\")\ - file:write(blob)\ - return file:close()\ - end\ - }\ - _base_0.__index = _base_0\ - _class_0 = setmetatable({\ - __init = function(self, opts)\ - if opts == nil then\ - opts = { }\ - end\ - opts.root = opts.root or 'root'\ - opts.verbose = opts.verbose or false\ - if not opts.verbose then\ - self.log = function() end\ - end\ - self.root = opts.root:match('^(.-)/?$')\ - return self:log(\"opening '\" .. tostring(opts.root) .. \"'...\")\ - end,\ - __base = _base_0,\ - __name = \"FSStore\"\ - }, {\ - __index = _base_0,\ - __call = function(cls, ...)\ - local _self_0 = setmetatable({}, _base_0)\ - cls.__init(_self_0, ...)\ - return _self_0\ - end\ - })\ - _base_0.__class = _class_0\ - FSStore = _class_0\ -end\ -return {\ - FSStore = FSStore\ -}\ -", "mmm/mmmfs/stores/fs.lua") end -if not p["mmm.mmmfs.stores"] then p["mmm.mmmfs.stores"] = load("local require = relative(..., 0)\ -local get_store\ -get_store = function(args, opts)\ - if args == nil then\ - args = 'sql'\ - end\ - if opts == nil then\ - opts = {\ - verbose = true\ - }\ - end\ - local type, arg = args:match('(%w+):(.*)')\ - if not (type) then\ - type = args\ - end\ - local _exp_0 = type:lower()\ - if 'sql' == _exp_0 then\ - local SQLStore\ - SQLStore = require('.sql').SQLStore\ - if arg == 'MEMORY' then\ - opts.memory = true\ - else\ - opts.file = arg\ - end\ - return SQLStore(opts)\ - elseif 'fs' == _exp_0 then\ - local FSStore\ - FSStore = require('.fs').FSStore\ - opts.root = arg\ - return FSStore(opts)\ - else\ - warn(\"unknown or missing value for STORE: valid types values are sql, fs\")\ - return os.exit(1)\ - end\ -end\ -return {\ - get_store = get_store\ -}\ -", "mmm/mmmfs/stores/init.lua") end -if not p["mmm.mmmfs.stores.sql"] then p["mmm.mmmfs.stores.sql"] = load("local sqlite = require('sqlite3')\ -local root = os.tmpname()\ -local SQLStore\ -do\ - local _class_0\ - local _base_0 = {\ - log = function(self, ...)\ - return print(\"[DB]\", ...)\ - end,\ - close = function(self)\ - return self.db:close()\ - end,\ - fetch = function(self, q, ...)\ - local stmt = assert(self.db:prepare(q))\ - if 0 < select('#', ...) then\ - stmt:bind(...)\ - end\ - return stmt:irows()\ - end,\ - fetch_one = function(self, q, ...)\ - local stmt = assert(self.db:prepare(q))\ - if 0 < select('#', ...) then\ - stmt:bind(...)\ - end\ - return stmt:first_irow()\ - end,\ - exec = function(self, q, ...)\ - local stmt = assert(self.db:prepare(q))\ - if 0 < select('#', ...) then\ - stmt:bind(...)\ - end\ - local res = assert(stmt:exec())\ - end,\ - list_fileders_in = function(self, path)\ - if path == nil then\ - path = ''\ - end\ - return coroutine.wrap(function()\ - for _des_0 in self:fetch('SELECT path\\n FROM fileder WHERE parent IS ?', path) do\ - path = _des_0[1]\ - coroutine.yield(path)\ - end\ - end)\ - end,\ - list_all_fileders = function(self, path)\ - if path == nil then\ - path = ''\ - end\ - return coroutine.wrap(function()\ - for path in self:list_fileders_in(path) do\ - coroutine.yield(path)\ - for p in self:list_all_fileders(path) do\ - coroutine.yield(p)\ - end\ - end\ - end)\ - end,\ - create_fileder = function(self, parent, name)\ - local path = tostring(parent) .. \"/\" .. tostring(name)\ - self:log(\"creating fileder \" .. tostring(path))\ - self:exec('INSERT INTO fileder (path, parent)\\n VALUES (:path, :parent)', {\ - path = path,\ - parent = parent\ - })\ - local changes = self:fetch_one('SELECT changes()')\ - assert(changes[1] == 1, \"couldn't create fileder - parent missing?\")\ - return path\ - end,\ - remove_fileder = function(self, path)\ - self:log(\"removing fileder \" .. tostring(path))\ - return self:exec('DELETE FROM fileder\\n WHERE path LIKE :path || \"/%\"\\n OR path = :path', path)\ - end,\ - rename_fileder = function(self, path, next_name)\ - self:log(\"renaming fileder \" .. tostring(path) .. \" -> '\" .. tostring(next_name) .. \"'\")\ - error('not implemented')\ - return self:exec('UPDATE fileder\\n SET path = parent || \"/\" || :next_name\\n WHERE path = :path', {\ - path = path,\ - next_name = next_name\ - })\ - end,\ - move_fileder = function(self, path, next_parent)\ - self:log(\"moving fileder \" .. tostring(path) .. \" -> \" .. tostring(next_parent) .. \"/\")\ - return error('not implemented')\ - end,\ - list_facets = function(self, path)\ - return coroutine.wrap(function()\ - for _des_0 in self:fetch('SELECT facet.name, facet.type\\n FROM facet\\n INNER JOIN fileder ON facet.fileder_id = fileder.id\\n WHERE fileder.path = ?', path) do\ - local name, type\ - name, type = _des_0[1], _des_0[2]\ - coroutine.yield(name, type)\ - end\ - end)\ - end,\ - load_facet = function(self, path, name, type)\ - local v = self:fetch_one('SELECT facet.value\\n FROM facet\\n INNER JOIN fileder ON facet.fileder_id = fileder.id\\n WHERE fileder.path = :path\\n AND facet.name = :name\\n AND facet.type = :type', {\ - path = path,\ - name = name,\ - type = type\ - })\ - return v and v[1]\ - end,\ - create_facet = function(self, path, name, type, blob)\ - self:log(\"creating facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\ - self:exec('INSERT INTO facet (fileder_id, name, type, value)\\n SELECT id, :name, :type, :blob\\n FROM fileder\\n WHERE fileder.path = :path', {\ - path = path,\ - name = name,\ - type = type,\ - blob = blob\ - })\ - local changes = self:fetch_one('SELECT changes()')\ - return assert(changes[1] == 1, \"couldn't create facet - fileder missing?\")\ - end,\ - remove_facet = function(self, path, name, type)\ - self:log(\"removing facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\ - self:exec('DELETE FROM facet\\n WHERE name = :name\\n AND type = :type\\n AND fileder_id = (SELECT id FROM fileder WHERE path = :path)', {\ - path = path,\ - name = name,\ - type = type\ - })\ - local changes = self:fetch_one('SELECT changes()')\ - return assert(changes[1] == 1, \"no such facet\")\ - end,\ - rename_facet = function(self, path, name, type, next_name)\ - self:log(\"renaming facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type) .. \" -> \" .. tostring(next_name))\ - self:exec('UPDATE facet\\n SET name = :next_name\\n WHERE name = :name\\n AND type = :type\\n AND fileder_id = (SELECT id FROM fileder WHERE path = :path)', {\ - path = path,\ - name = name,\ - next_name = next_name,\ - type = type\ - })\ - local changes = self:fetch_one('SELECT changes()')\ - return assert(changes[1] == 1, \"no such facet\")\ - end,\ - update_facet = function(self, path, name, type, blob)\ - self:log(\"updating facet \" .. tostring(path) .. \" | \" .. tostring(name) .. \": \" .. tostring(type))\ - self:exec('UPDATE facet\\n SET value = :blob\\n WHERE facet.name = :name\\n AND facet.type = :type\\n AND facet.fileder_id = (SELECT id FROM fileder WHERE path = :path)', {\ - path = path,\ - name = name,\ - type = type,\ - blob = blob\ - })\ - local changes = self:fetch_one('SELECT changes()')\ - return assert(changes[1] == 1, \"no such facet\")\ - end\ - }\ - _base_0.__index = _base_0\ - _class_0 = setmetatable({\ - __init = function(self, opts)\ - if opts == nil then\ - opts = { }\ - end\ - opts.file = opts.file or 'db.sqlite3'\ - opts.verbose = opts.verbose or false\ - opts.memory = opts.memory or false\ - if not opts.verbose then\ - self.log = function() end\ - end\ - if opts.memory then\ - self:log(\"opening in-memory DB...\")\ - self.db = sqlite.open_memory()\ - else\ - self:log(\"opening '\" .. tostring(opts.file) .. \"'...\")\ - self.db = sqlite.open(opts.file)\ - end\ - return assert(self.db:exec([[ PRAGMA foreign_keys = ON;\ - PRAGMA case_sensitive_like = ON;\ - CREATE TABLE IF NOT EXISTS fileder (\ - id INTEGER NOT NULL PRIMARY KEY,\ - path TEXT NOT NULL UNIQUE,\ - parent TEXT REFERENCES fileder(path)\ - ON DELETE CASCADE\ - ON UPDATE CASCADE\ - );\ - INSERT OR IGNORE INTO fileder (path, parent) VALUES (\"\", NULL);\ -\ - CREATE TABLE IF NOT EXISTS facet (\ - fileder_id INTEGER NOT NULL\ - REFERENCES fileder\ - ON UPDATE CASCADE\ - ON DELETE CASCADE,\ - name TEXT NOT NULL,\ - type TEXT NOT NULL,\ - value BLOB NOT NULL,\ - PRIMARY KEY (fileder_id, name, type)\ - );\ - CREATE INDEX IF NOT EXISTS facet_fileder_id ON facet(fileder_id);\ - CREATE INDEX IF NOT EXISTS facet_name ON facet(name);\ - ]]))\ - end,\ - __base = _base_0,\ - __name = \"SQLStore\"\ - }, {\ - __index = _base_0,\ - __call = function(cls, ...)\ - local _self_0 = setmetatable({}, _base_0)\ - cls.__init(_self_0, ...)\ - return _self_0\ - end\ - })\ - _base_0.__class = _class_0\ - SQLStore = _class_0\ -end\ -return {\ - SQLStore = SQLStore\ -}\ -", "mmm/mmmfs/stores/sql.lua") end -if not p["mmm.dom"] then p["mmm.dom"] = load("local element\ -element = function(element)\ - return function(...)\ - local children = {\ - ...\ - }\ - local attributes = children[#children]\ - if 'table' == (type(attributes)) and not attributes.node then\ - table.remove(children)\ - else\ - attributes = { }\ - end\ - do\ - local e = document:createElement(element)\ - for k, v in pairs(attributes) do\ - if k == 'class' then\ - k = 'className'\ - end\ - if k == 'style' and 'table' == type(v) then\ - for kk, vv in pairs(v) do\ - e.style[kk] = vv\ - end\ - elseif 'string' == type(k) then\ - e[k] = v\ - end\ - end\ - if #children == 0 then\ - children = attributes\ - end\ - for _index_0 = 1, #children do\ - local child = children[_index_0]\ - if 'string' == type(child) then\ - child = document:createTextNode(child)\ - end\ - e:appendChild(child)\ - end\ - return e\ - end\ - end\ -end\ -return setmetatable({ }, {\ - __index = function(self, name)\ - do\ - local val = element(name)\ - self[name] = val\ - return val\ - end\ - end\ -})\ -", "mmm/dom/init.client.lua") end -if not p["mmm.component"] then p["mmm.component"] = load("local tohtml\ -tohtml = function(val)\ - if 'string' == type(val) then\ - return document:createTextNode(val)\ - end\ - if 'table' == type(val) then\ - assert(val.node, \"Table doesn't have .node\")\ - val = val.node\ - end\ - if 'userdata' == type(val) then\ - assert((js.instanceof(val, js.global.Node)), \"userdata is not a Node\")\ - return val\ - else\ - return error(\"not a Node: \" .. tostring(val) .. \", \" .. tostring(type(val)))\ - end\ -end\ -local text\ -text = function(str)\ - return document:createTextNode(tostring(str))\ -end\ -local ReactiveVar\ -do\ - local _class_0\ - local _base_0 = {\ - set = function(self, value)\ - local old = self.value\ - self.value = value\ - for k, callback in pairs(self.listeners) do\ - callback(self.value, old)\ - end\ - end,\ - get = function(self)\ - return self.value\ - end,\ - transform = function(self, transform)\ - return self:set(transform(self:get()))\ - end,\ - subscribe = function(self, callback)\ - do\ - local _with_0\ - _with_0 = function()\ - self.listeners[callback] = nil\ - end\ - self.listeners[callback] = callback\ - return _with_0\ - end\ - end,\ - map = function(self, transform)\ - do\ - local _with_0 = ReactiveVar(transform(self.value))\ - _with_0.upstream = self:subscribe(function(...)\ - return _with_0:set(transform(...))\ - end)\ - return _with_0\ - end\ - end\ - }\ - _base_0.__index = _base_0\ - _class_0 = setmetatable({\ - __init = function(self, value)\ - self.value = value\ - self.listeners = setmetatable({ }, {\ - __mode = 'kv'\ - })\ - end,\ - __base = _base_0,\ - __name = \"ReactiveVar\"\ - }, {\ - __index = _base_0,\ - __call = function(cls, ...)\ - local _self_0 = setmetatable({}, _base_0)\ - cls.__init(_self_0, ...)\ - return _self_0\ - end\ - })\ - _base_0.__class = _class_0\ - local self = _class_0\ - self.isinstance = function(val)\ - return 'table' == (type(val)) and val.subscribe\ - end\ - ReactiveVar = _class_0\ -end\ -local ReactiveElement\ -do\ - local _class_0\ - local _base_0 = {\ - destroy = function(self)\ - local _list_0 = self._subscriptions\ - for _index_0 = 1, #_list_0 do\ - local unsub = _list_0[_index_0]\ - unsub()\ - end\ - end,\ - set = function(self, attr, value)\ - if attr == 'class' then\ - attr = 'className'\ - end\ - if 'table' == (type(value)) and ReactiveVar.isinstance(value) then\ - table.insert(self._subscriptions, value:subscribe(function(...)\ - return self:set(attr, ...)\ - end))\ - value = value:get()\ - end\ - if attr == 'style' and 'table' == type(value) then\ - for k, v in pairs(value) do\ - self.node.style[k] = v\ - end\ - return \ - end\ - self.node[attr] = value\ - end,\ - prepend = function(self, child, last)\ - return self:append(child, last, 'prepend')\ - end,\ - append = function(self, child, last, mode)\ - if mode == nil then\ - mode = 'append'\ - end\ - if ReactiveVar.isinstance(child) then\ - table.insert(self._subscriptions, child:subscribe(function(...)\ - return self:append(...)\ - end))\ - child = child:get()\ - end\ - if 'string' == type(last) then\ - error('cannot replace string node')\ - end\ - if child == nil then\ - if last then\ - self:remove(last)\ - end\ - return \ - end\ - child = tohtml(child)\ - if last then\ - return self.node:replaceChild(child, tohtml(last))\ - else\ - local _exp_0 = mode\ - if 'append' == _exp_0 then\ - return self.node:appendChild(child)\ - elseif 'prepend' == _exp_0 then\ - return self.node:insertBefore(child, self.node.firstChild)\ - end\ - end\ - end,\ - remove = function(self, child)\ - self.node:removeChild(tohtml(child))\ - if 'table' == (type(child)) and child.destroy then\ - return child:destroy()\ - end\ - end\ - }\ - _base_0.__index = _base_0\ - _class_0 = setmetatable({\ - __init = function(self, element, ...)\ - if 'userdata' == type(element) then\ - self.node = element\ - else\ - self.node = document:createElement(element)\ - end\ - self._subscriptions = { }\ - local children = {\ - ...\ - }\ - local attributes = children[#children]\ - if 'table' == (type(attributes)) and (not ReactiveElement.isinstance(attributes)) and (not ReactiveVar.isinstance(attributes)) then\ - table.remove(children)\ - else\ - attributes = { }\ - end\ - for k, v in pairs(attributes) do\ - if 'string' == type(k) then\ - self:set(k, v)\ - end\ - end\ - if #children == 0 then\ - children = attributes\ - end\ - for _index_0 = 1, #children do\ - local child = children[_index_0]\ - self:append(child)\ - end\ - end,\ - __base = _base_0,\ - __name = \"ReactiveElement\"\ - }, {\ - __index = _base_0,\ - __call = function(cls, ...)\ - local _self_0 = setmetatable({}, _base_0)\ - cls.__init(_self_0, ...)\ - return _self_0\ - end\ - })\ - _base_0.__class = _class_0\ - local self = _class_0\ - self.isinstance = function(val)\ - return 'table' == (type(val)) and val.node\ - end\ - ReactiveElement = _class_0\ -end\ -local get_or_create\ -get_or_create = function(elem, id, ...)\ - elem = (document:getElementById(id)) or elem\ - do\ - local _with_0 = ReactiveElement(elem, ...)\ - _with_0:set('id', id)\ - return _with_0\ - end\ -end\ -local elements = setmetatable({ }, {\ - __index = function(self, name)\ - do\ - local val\ - val = function(...)\ - return ReactiveElement(name, ...)\ - end\ - self[name] = val\ - return val\ - end\ - end\ -})\ -return {\ - ReactiveVar = ReactiveVar,\ - ReactiveElement = ReactiveElement,\ - get_or_create = get_or_create,\ - tohtml = tohtml,\ - text = text,\ - elements = elements\ -}\ -", "mmm/component/init.client.lua") end diff --git a/root/static/style/text$css.css b/root/static/style/text$css.css deleted file mode 100644 index c0dc484..0000000 --- a/root/static/style/text$css.css +++ /dev/null @@ -1,411 +0,0 @@ -:root { - --gray-bright: #eeeeee; - --gray-dark: #303336; - --gray-darker: #1d1f21; - --gray-neutral: #b9bdc1; - --gray-success: #bdddc1; - --gray-fail: #ddbdc1; - --margin-wide: 2rem; } - @media only screen and (max-width: 425px) { - :root { - --margin-wide: 0.5rem; } } - -* { - font-weight: inherit; - font-style: inherit; - font-family: inherit; - color: inherit; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; } - -body, html, h1, h2, h3, h4, h5, h6 { - margin: 0; - padding: 0; } - -h1, h2, h3, h4, h5, h6 { - font-weight: bold; } - -input, select, button { - color: initial; } - -tt, code, kbd, samp { - font-family: monospace; } - -code { - font-size: 0.8em; } - -b, strong { - font-weight: bold; } - -em, i { - font-style: italic; } - -a { - font-size: 1em; - cursor: pointer; } - -hr { - clear: both; } - -ul { - margin: 0; } - -body { - display: flex; - flex-direction: column; - justify-content: space-between; - background: #ffffff; - font-family: sans-serif; - min-height: 100vh; } - -a { - display: inline-block; - font-weight: bold; - text-decoration: underline; - text-decoration-color: transparent; - transition: filter 500ms, text-decoration-color 500ms; } - a:hover { - filter: invert(40%); - text-decoration-color: currentColor; } - -::selection { - background: #303336; - color: #eeeeee; - padding: 1em; } - -/* - -vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid) - -*/ -/*background color*/ -.hljs { - background: #1d1f21; - border-radius: 6px; - padding: 0.2em 0.5em; - white-space: nowrap; } - -pre > .hljs { - display: block; - overflow-x: auto; - padding: 1em; - white-space: pre-wrap; - margin: 0 2em; } - -/*selection color*/ -.hljs::selection, -.hljs span::selection { - background: #373b41; } - -.hljs::-moz-selection, -.hljs span::-moz-selection { - background: #373b41; } - -/*foreground color*/ -.hljs { - color: #c5c8c6; } - -/*color: fg_yellow*/ -.hljs-title, -.hljs-name { - color: #f0c674; } - -/*color: fg_comment*/ -.hljs-comment, -.hljs-meta, -.hljs-meta .hljs-keyword { - color: #707880; } - -/*color: fg_red*/ -.hljs-number, -.hljs-symbol, -.hljs-literal, -.hljs-deletion, -.hljs-link { - color: #cc6666; } - -/*color: fg_green*/ -.hljs-string, -.hljs-doctag, -.hljs-addition, -.hljs-regexp, -.hljs-selector-attr, -.hljs-selector-pseudo { - color: #b5bd68; } - -/*color: fg_purple*/ -.hljs-attribute, -.hljs-code, -.hljs-selector-id { - color: #b294bb; } - -/*color: fg_blue*/ -.hljs-keyword, -.hljs-selector-tag, -.hljs-bullet, -.hljs-tag { - color: #81a2be; } - -/*color: fg_aqua*/ -.hljs-subst, -.hljs-variable, -.hljs-template-tag, -.hljs-template-variable { - color: #8abeb7; } - -/*color: fg_orange*/ -.hljs-type, -.hljs-built_in, -.hljs-builtin-name, -.hljs-quote, -.hljs-section, -.hljs-selector-class { - color: #de935f; } - -.hljs-emphasis { - font-style: italic; } - -.hljs-strong { - font-weight: bold; } - -header > div { - font-family: 'Source Sans Pro', sans-serif; - padding: 1rem 2rem; - text-align: right; - color: #eeeeee; - background: #303336; } - header > div h1 { - display: flex; - justify-content: flex-end; - align-items: center; - flex-wrap: wrap; - margin: 0; - line-height: 5rem; - font-size: 4rem; - font-weight: 200; } - header > div h1 > span { - margin-left: auto; } - header > div h1 .bold { - font-weight: 400; } - header > div h1 > a { - height: 5rem; } - header > div h1 .sun { - height: 100%; - stroke: currentColor; - fill: currentColor; } - header > div h1 .sun .out, header > div h1 .sun .in { - animation: spin 2s; - animation-iteration-count: 1; - transform: scale(1); } - header > div h1 .sun .in { - animation: size 2s; } - header > div h1 .sun.spin .circle { - animation: none; } - -header aside { - margin: 0; - padding: 0 2rem; - color: #eeeeee; - background: #1d1f21; - line-height: 3em; } - header aside > a { - margin-right: 2em; } - -@keyframes spin { - 0% { - transform: rotate3d(0.5, 1, 0, 0turn); } - 100% { - transform: rotate3d(0.5, 1, 0, 1turn); } } - -@keyframes size { - 0%, 100% { - transform: scale(1); } - 40%, 60% { - transform: scale(1.8); } } - -footer { - display: flex; - padding: 1rem 2rem; - position: sticky; - bottom: 0; - color: #eeeeee; - background: #303336; } - footer .icons { - flex: 1; - display: flex; - justify-content: flex-end; } - footer .icons .iconlink { - filter: invert(0.7); } - footer .icons .iconlink:hover { - filter: invert(1); } - footer .icons .iconlink > img { - height: 1em; - margin-left: 0.5em; - vertical-align: middle; } - -.browser { - display: flex; - flex: 1; - border-top: 0.2rem solid #eeeeee; } - -.view { - display: flex; - flex-direction: column; - flex: 1 1 0; - min-width: 0; } - .view.inspector { - top: 0; - position: sticky; - max-height: 100vh; - color: #c5c8c6; - border-style: solid; - border-width: 0 0 0 0.6rem; - border-radius: 0 6px 6px 0; - border-color: #303336; - background: #303336; } - .view.inspector nav { - background: inherit; } - .view.inspector .content { - margin: 0; - padding: 0; - display: flex; - background: #1d1f21; } - .view.inspector .content > * { - display: block; - margin: 0; - padding: 1em; - border-radius: 0; - border: 0; - flex: 1; } - .view nav { - position: sticky; - top: 0; - display: flex; - flex: 0 0 auto; - flex-wrap: wrap; - justify-content: space-between; - background: #eeeeee; - z-index: 1000; } - .view nav > span:first-of-type { - flex: 1 0 auto; } - .view nav > * { - margin: 1em; - white-space: nowrap; } - @media only screen and (max-width: 425px) { - .view nav > .inspect-btn { - display: none; } } - .view .error-wrap { - flex: 0 0 auto; - padding: 1em 2em; - overflow: hidden; - background: #ddbdc1; } - .view .error-wrap.empty { - display: none; } - .view .error-wrap > span { - display: inline-block; - margin-bottom: 0.5em; - font-weight: bold; - color: #f00; } - .view .error-wrap > pre { - margin: 0; } - .view .content { - flex: 1 1 auto; - overflow: auto; - padding: 1em 2em; - position: relative; } - -.content { - opacity: 1; - transition: opacity 150ms; } - body.loading .content { - opacity: 0; } - -.content img, .content video { - width: inherit; - height: inherit; } - -.content .markdown > img, .content .markdown > video, -.content .markdown > p > img, -.content .markdown > p > video, -.content .markdown > p > a > img, -.content .markdown > p > a > video, -.content .markdown > a > img, -.content .markdown > a > video { - display: block; - max-width: 100%; - max-height: 50vh; - padding: 0 2em; - box-sizing: border-box; } - -.content .embed { - width: inherit; - height: inherit; } - .content .embed .description { - text-align: center; } - .content .embed.inline { - display: inline-block; } - .content .embed.desc { - display: inline-block; - padding: 0.5em; - margin: 0.2em; - background: #eeeeee; } - -.content pre > code { - border-style: solid; - border-width: 0 0 0 0.6rem; - border-radius: 0 6px 6px 0; - border-color: #303336; - display: block; - border-radius: 6px; - margin: 0 var(--margin-wide); - padding: 1em; - white-space: pre-wrap; - overflow-x: auto; - background: #1d1f21; - color: #c5c8c6; } - -.content pre.dual-code { - display: flex; - justify-content: space-between; - padding: 0 2rem; } - .content pre.dual-code > code { - border-style: solid; - border-width: 0 0.3rem 0 0; - border-radius: 6px 0 0 6px; - flex: 1; - margin: 0; } - .content pre.dual-code > code + code { - border-style: solid; - border-width: 0 0 0 0.3rem; - border-radius: 0 6px 6px 0; } - -.content .example, .content .well { - border-style: solid; - border-width: 0 0 0 0.6rem; - border-radius: 0 6px 6px 0; - margin: 1rem var(--margin-wide); - padding: 1rem; - background: #eeeeee; - border-color: #b9bdc1; } - -.canvas_app { - position: relative; - display: inline-block; } - .canvas_app .overlay { - position: absolute; - padding: 1rem; - top: 0; - left: 0; - right: 0; - bottom: 0; - opacity: 0; - background: rgba(0, 0, 0, 0.7); - transition: opacity 300ms; } - .canvas_app .overlay:hover { - opacity: 1; } - .canvas_app .overlay > * { - margin: 0.5em; } - .canvas_app .overlay a { - display: block; - color: #eeeeee; - font-family: inherit; } -- cgit v1.2.3 From 9436588d01db772366ee69a106a6de874bbb844e Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 10 Oct 2019 19:53:10 +0200 Subject: add table to mmm/dom convert --- build/server.moon | 2 +- mmm/mmmfs/converts.moon | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/build/server.moon b/build/server.moon index 17c26aa..706e4e0 100644 --- a/build/server.moon +++ b/build/server.moon @@ -71,7 +71,7 @@ class Server -- '?index': one level deep -- '?tree': recursively index = fileder\get_index facet.name == '?tree' - convert 'table', facet.type, index + convert 'table', facet.type, index, fileder, facet.name else -- fileder and facet given if not fileder\has_facet facet.name diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon index 823033e..5fddc60 100644 --- a/mmm/mmmfs/converts.moon +++ b/mmm/mmmfs/converts.moon @@ -1,5 +1,5 @@ require = relative ..., 1 -import div, code, img, video, blockquote, a, span, source, iframe from require 'mmm.dom' +import div, pre, code, img, video, blockquote, a, span, source, iframe from require 'mmm.dom' import find_fileder, link_to, embed from (require 'mmm.mmmfs.util') require 'mmm.dom' import render from require '.layout' import tohtml from require 'mmm.component' @@ -234,6 +234,23 @@ converts = { error "unknown type '#{type obj}'" (val) => tojson val + }, + { + inp: 'table', + out: 'mmm/dom', + transform: do + deep_tostring = (tbl, space='') -> + buf = space .. tostring tbl + + return buf unless 'table' == type tbl + + buf = buf .. ' {\n' + for k,v in pairs tbl + buf = buf .. "#{space} [#{k}]: #{deep_tostring v, space .. ' '}\n" + buf = buf .. "#{space}}" + buf + + (tbl) => pre code deep_tostring tbl } } -- cgit v1.2.3 From e2a4257fc05d37822df2b7bbe0f587645375edf2 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 11 Oct 2019 12:15:58 +0200 Subject: fileders load via get_index rather than list_facets/list_fileders --- build/server.moon | 8 ++++-- mmm/init.client.moon | 6 +++- mmm/init.server.moon | 6 +++- mmm/mmmfs/fileder.moon | 34 +++++++++++----------- mmm/mmmfs/stores/fs.moon | 20 ++++--------- mmm/mmmfs/stores/init.moon | 32 +++++++++++++++++++++ mmm/mmmfs/stores/sql.moon | 21 ++++---------- mmm/mmmfs/stores/web.moon | 46 +++++++++++++++++------------- spec/stores_spec.moon | 70 ++++++++++++++++++++++++++++++++++++++++++++-- 9 files changed, 170 insertions(+), 73 deletions(-) diff --git a/build/server.moon b/build/server.moon index 706e4e0..89cf1a6 100644 --- a/build/server.moon +++ b/build/server.moon @@ -60,7 +60,10 @@ class Server local browser = require 'mmm.mmmfs.browser' local fileder = require 'mmm.mmmfs.fileder' local web = require 'mmm.mmmfs.stores.web' - local root = fileder.Fileder(web.WebStore({ verbose = true }), path) + + local store = web.WebStore({ verbose = true }) + local index = store:get_index(path, -1) + local root = fileder.Fileder(store, index) BROWSER = browser.Browser(root, path, true) end) @@ -70,7 +73,8 @@ class Server -- serve fileder index -- '?index': one level deep -- '?tree': recursively - index = fileder\get_index facet.name == '?tree' + depth = if facet.name == '?tree' then -1 else 1 + index = @store\get_index path, depth convert 'table', facet.type, index, fileder, facet.name else -- fileder and facet given diff --git a/mmm/init.client.moon b/mmm/init.client.moon index c29a675..e32f25d 100644 --- a/mmm/init.client.moon +++ b/mmm/init.client.moon @@ -40,7 +40,11 @@ relative = do base = base\match '^(.*)%.%w+$' (name, x) -> - name = base .. name if '.' == name\sub 1, 1 + if name == '.' + name = base + else if '.' == name\sub 1, 1 + name = base .. name + _require name if on_load diff --git a/mmm/init.server.moon b/mmm/init.server.moon index 8fc6a0e..0fe36d5 100644 --- a/mmm/init.server.moon +++ b/mmm/init.server.moon @@ -35,5 +35,9 @@ relative = do base = base\match '^(.*)%.%w+$' (name, x) -> - name = base .. name if '.' == name\sub 1, 1 + if name == '.' + name = base + else if '.' == name\sub 1, 1 + name = base .. name + _require name diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index b7876a3..0d484b5 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -134,14 +134,26 @@ class Fileder @facet_keys[k] = v } - load: => + -- this fails with JS objects from JSON.parse + if 'table' == type @path + index = @path + @path = index.path + @load index + + assert ('string' == type @path), "invalid path: '#{@path}'" + + load: (index) => + assert not @loaded, "already loaded!" @loaded = true - for path in @store\list_fileders_in @path - table.insert @children, Fileder @store, path + if not index + index = @store\get_index @path + + for path_or_index in *index.children + table.insert @children, Fileder @store, path_or_index - for name, type in @store\list_facets @path - key = Key name, type + for key in *index.facets + key = Key key @facet_keys[key] = key _, name = dir_base @path @@ -195,18 +207,6 @@ class Fileder [name for name in pairs names] - -- get an index table, listing path, facets and children - -- optionally get recursive index - get_index: (recursive=false) => - { - path: @path - facets: [key for str, key in pairs @facet_keys] - children: if recursive - [child\get_index true for child in *@children] - else - [{ :path } for { :path } in *@children] - } - -- check whether a facet is directly available has: (...) => want = Key ... diff --git a/mmm/mmmfs/stores/fs.moon b/mmm/mmmfs/stores/fs.moon index ac20232..5167668 100644 --- a/mmm/mmmfs/stores/fs.moon +++ b/mmm/mmmfs/stores/fs.moon @@ -1,4 +1,6 @@ +require = relative ..., 1 lfs = require 'lfs' +import Store from require '.' -- split filename into dirname + basename dir_base = (path) -> @@ -8,21 +10,16 @@ dir_base = (path) -> dir, base -class FSStore +class FSStore extends Store new: (opts = {}) => - opts.root or= 'root' - opts.verbose or= false + super opts - if not opts.verbose - @log = -> + opts.root or= 'root' -- ensure path doesnt end with a slash @root = opts.root\match '^(.-)/?$' @log "opening '#{opts.root}'..." - log: (...) => - print "[DB]", ... - -- fileders list_fileders_in: (path='') => coroutine.wrap -> @@ -32,13 +29,6 @@ class FSStore if 'directory' == lfs.attributes entry_path, 'mode' coroutine.yield "#{path}/#{entry_name}" - list_all_fileders: (path='') => - coroutine.wrap -> - for path in @list_fileders_in path - coroutine.yield path - for p in @list_all_fileders path - coroutine.yield p - create_fileder: (parent, name) => @log "creating fileder #{path}" path = "#{parent}/#{name}" diff --git a/mmm/mmmfs/stores/init.moon b/mmm/mmmfs/stores/init.moon index 64fc44d..bbca33f 100644 --- a/mmm/mmmfs/stores/init.moon +++ b/mmm/mmmfs/stores/init.moon @@ -1,5 +1,36 @@ require = relative ..., 0 +class Store + new: (opts) => + opts.verbose or= false + + if not opts.verbose + @log = -> + + list_fileders_in: => error "not implemented" + + list_all_fileders: (path='') => + coroutine.wrap -> + for path in @list_fileders_in path + coroutine.yield path + for p in @list_all_fileders path + coroutine.yield p + + get_index: (path='', depth=1) => + if depth == 0 + return path + + { + :path + facets: [{:name, :type} for name, type in @list_facets path] + children: [@get_index child, depth - 1 for child in @list_fileders_in path] + } + + close: => + + log: (...) => + print "[#{@@__name}]", ... + -- instantiate a store from a CLI arg -- e.g.: sql, fs:/path/to/root, sql:MEMORY, sql:db.sqlite3 get_store = (args='sql', opts={verbose: true}) -> @@ -29,5 +60,6 @@ get_store = (args='sql', opts={verbose: true}) -> os.exit 1 { + :Store :get_store } diff --git a/mmm/mmmfs/stores/sql.moon b/mmm/mmmfs/stores/sql.moon index 490eade..1d50877 100644 --- a/mmm/mmmfs/stores/sql.moon +++ b/mmm/mmmfs/stores/sql.moon @@ -1,15 +1,14 @@ +require = relative ..., 1 sqlite = require 'sqlite3' -root = os.tmpname! +import Store from require '.' -class SQLStore +class SQLStore extends Store new: (opts = {}) => + super opts + opts.file or= 'db.sqlite3' - opts.verbose or= false opts.memory or= false - if not opts.verbose - @log = -> - if opts.memory @log "opening in-memory DB..." @db = sqlite.open_memory! @@ -43,9 +42,6 @@ class SQLStore CREATE INDEX IF NOT EXISTS facet_name ON facet(name); ]] - log: (...) => - print "[DB]", ... - close: => @db\close! @@ -71,13 +67,6 @@ class SQLStore FROM fileder WHERE parent IS ?', path coroutine.yield path - list_all_fileders: (path='') => - coroutine.wrap -> - for path in @list_fileders_in path - coroutine.yield path - for p in @list_all_fileders path - coroutine.yield p - create_fileder: (parent, name) => path = "#{parent}/#{name}" diff --git a/mmm/mmmfs/stores/web.moon b/mmm/mmmfs/stores/web.moon index adf3ee4..082fea8 100644 --- a/mmm/mmmfs/stores/web.moon +++ b/mmm/mmmfs/stores/web.moon @@ -1,3 +1,7 @@ +require = relative ..., 1 +import Store from require '.' +{ :location, :XMLHttpRequest, :JSON, :Object, :Array } = js.global + -- split filename into dirname + basename dir_base = (path) -> dir, base = path\match '(.-)([^/]-)$' @@ -6,7 +10,6 @@ dir_base = (path) -> dir, base -{ :location, :XMLHttpRequest, :JSON } = js.global fetch = (url) -> request = js.new XMLHttpRequest request\open 'GET', url, false @@ -15,38 +18,46 @@ fetch = (url) -> assert request.status == 200, "unexpected status code: #{request.status}" request.responseText -class WebStore +parse_json = do + fix = (val) -> + switch type val + when 'userdata' + if Array\isArray val + [fix x for x in js.of val] + else + {(fix e[0]), (fix e[1]) for e in js.of Object\entries(val)} + else + val + + (string) -> + print fix JSON\parse string + fix JSON\parse string + +class WebStore extends Store new: (opts = {}) => + super opts + if MODE == 'CLIENT' origin = location.origin opts.host or= origin - opts.verbose or= false - - if not opts.verbose - @log = -> -- ensure host ends without a slash @host = opts.host\match '^(.-)/?$' @log "connecting to '#{@host}'..." - log: (...) => - print "[DB]", ... + get_index: (path='', depth=1) => + pseudo = if depth > 1 or depth < 0 '?tree' else '?index' + json = fetch "#{@host .. path}/#{pseudo}: application/json" + parse_json json -- fileders list_fileders_in: (path='') => coroutine.wrap -> json = fetch "#{@host .. path}/?index: application/json" - index = JSON\parse json + index = parse_json json for child in js.of index.children coroutine.yield child.path - list_all_fileders: (path='') => - coroutine.wrap -> - for path in @list_fileders_in path - coroutine.yield path - for p in @list_all_fileders path - coroutine.yield p - create_fileder: (parent, name) => @log "creating fileder #{path}" error "not implemented" @@ -70,9 +81,6 @@ class WebStore index = JSON\parse json for facet in js.of index.facets coroutine.yield facet.name, facet.type - -- @TODO: this doesn't belong here! - if facet.type\match 'text/moonscript' - coroutine.yield facet.name, facet.type\gsub 'text/moonscript', 'text/lua' load_facet: (path, name, type) => fetch "#{@host .. path}/#{name}: #{type}" diff --git a/spec/stores_spec.moon b/spec/stores_spec.moon index 3997ded..742d8c8 100644 --- a/spec/stores_spec.moon +++ b/spec/stores_spec.moon @@ -1,3 +1,21 @@ +-- relative imports +_G.relative = do + _require = require + + (base, sub) -> + sub = sub or 0 + + for i=1, sub + base = base\match '^(.*)%.%w+$' + + (name, x) -> + if name == '.' + name = base + else if '.' == name\sub 1, 1 + name = base .. name + + _require name + sort2 = (a, b) -> {ax, ay}, {bx, by} = a, b "#{ax}//#{ay}" < "#{bx}//#{by}" @@ -57,6 +75,51 @@ test_store = (ts) -> assert.are.same {{'', 'text/markdown'}, {'name', 'alpha'}}, toseq2 ts\list_facets '/hello/world' + describe "can get indexes", -> + hello_index = { + path: '/hello' + children: { + '/hello/world' + } + facets: { + { name: 'name', type: 'alpha' } + } + } + + it "for a single level", -> + assert.are.same hello_index, ts\get_index '/hello' + + + root_index = { + path: '' + children: { + hello_index + } + facets: {} + } + it "for a limited number of levels", -> + assert.are.same root_index, ts\get_index '', 2 + + it "recursively", -> + hello_index.children[1] = { + path: '/hello/world' + children: { + { + path: '/hello/world/again' + children: {} + facets: {} + } + } + facets: { + { name: '', type: 'text/markdown' } + { name: 'name', type: 'alpha' } + } + } + + assert.are.same root_index, ts\get_index '', -1 + + it "can get indexes recursively", -> + it "can load facets", -> assert.are.equal 'hello', ts\load_facet '/hello', 'name', 'alpha' assert.are.equal 'world', ts\load_facet '/hello/world', 'name', 'alpha' @@ -89,7 +152,10 @@ test_store = (ts) -> ts\remove_fileder '/hello' assert.are.same {}, toseq ts\list_all_fileders! -describe "SQL spec", -> + it "can be closed", -> + ts\close! + +describe "SQL store", -> import SQLStore from require 'mmm.mmmfs.stores.sql' test_store SQLStore memory: true @@ -105,7 +171,7 @@ describe "FS store", -> assert os.remove root assert lfs.mkdir root - test_store LFSStore :root + test_store FSStore :root teardown -> assert lfs.rmdir root -- cgit v1.2.3 From 782d0725f3f29eaa7d4a12213fb00c6643795348 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 11 Oct 2019 13:00:16 +0200 Subject: add key_spec --- mmm/mmmfs/fileder.moon | 11 +++++----- spec/key_spec.moon | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ spec/stores_spec.moon | 30 +------------------------- spec/test_util.moon | 34 +++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 34 deletions(-) create mode 100644 spec/key_spec.moon create mode 100644 spec/test_util.moon diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index 0d484b5..8c89083 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -20,18 +20,19 @@ class Key if 'string' == type second @name, @type = (opts or ''), second elseif 'string' == type opts - @name, @type = opts\match '^([%w-_]+): *(.+)$' + @name, @type = opts\match '^([%w-_]*): *(.+)$' if not @name @name = '' - @type = opts + @type = opts\match '^ *(.+)$' elseif 'table' == type opts - @name = opts.name + @name = opts.name or '' @type = opts.type - @original = opts.original - @filename = opts.filename else error "wrong argument type: #{type opts}, #{type second}" + assert ('string' == type @name), "name is not a string: '#{@name}'" + assert ('string' == type @type), "type is not a string: '#{@type}'" + -- format as a string (see constructor) tostring: => if @name == '' diff --git a/spec/key_spec.moon b/spec/key_spec.moon new file mode 100644 index 0000000..9b7dde4 --- /dev/null +++ b/spec/key_spec.moon @@ -0,0 +1,58 @@ +require 'spec.test_util' +package.loaded['mmm.mmmfs.conversion'] = {} +import Key from require 'mmm.mmmfs.fileder' + +nt = (name, type) -> :name, :type + +describe "Key", -> + it "can be instantiated from a string", -> + assert.are.same (nt '', 'type/only'), Key 'type/only' + assert.are.same (nt '', 'type/only'), Key ':type/only' + assert.are.same (nt '', 'the/type'), Key ' the/type' + assert.are.same (nt '', 'the/type'), Key ': the/type' + assert.are.same (nt '', 'URL -> long/type -> some/type'), Key 'URL -> long/type -> some/type' + + assert.are.same (nt 'facet_name', 'some/type'), Key 'facet_name: some/type' + assert.are.same (nt 'spacious_name', 'and/type'), Key 'spacious_name: and/type' + assert.are.same (nt 'name', 'URL -> long/type -> some/type'), Key 'name: URL -> long/type -> some/type' + + it "can be instantiated from two strings", -> + assert.are.same (nt '', 'type/only'), Key '', 'type/only' + assert.are.same (nt '', 'type/only'), Key nil, 'type/only' + assert.are.same (nt 'facet_name', 'some/type'), Key 'facet_name', 'some/type' + + assert.are.same (nt 'name', 'URL -> long/type -> some/type'), Key 'name', 'URL -> long/type -> some/type' + assert.are.same (nt '', 'URL -> long/type -> some/type'), Key '', 'URL -> long/type -> some/type' + + assert.are.same (nt 'spacious_name', ' and/type'), Key 'spacious_name', ' and/type' + assert.are.same (nt '', ' the/type'), Key nil, ' the/type' + + it "can be instantiated from a table or instance", -> + assert.are.same (nt '', 'type/only'), Key Key '', 'type/only' + assert.are.same (nt '', 'type/only'), Key nt '', 'type/only' + assert.are.same (nt '', 'type/only'), Key nt nil, 'type/only' + + assert.are.same (nt 'facet', 'the/type+extra'), Key Key 'facet', 'the/type+extra' + assert.are.same (nt 'facet', 'the/type+extra'), Key nt 'facet', 'the/type+extra' + + it "throws an error otherwise", -> + assert.has_error -> Key! + assert.has_error -> Key true + assert.has_error -> Key true, false + assert.has_error -> Key 4 + assert.has_error -> Key 4, 5 + assert.has_error -> Key {} + assert.has_error -> Key type: true + + it "tostring formats the key", -> + assert.is.equal 'type/only', tostring Key 'type/only' + assert.is.equal 'type/only', tostring Key '', 'type/only' + assert.is.equal 'type/only', tostring Key ": type/only" + + assert.is.equal 'facet: and/type+extra', tostring Key 'facet: and/type+extra' + assert.is.equal 'facet: and/type+extra', tostring Key 'facet', 'and/type+extra' + assert.is.equal 'facet: and/type+extra', tostring Key 'facet: and/type+extra' + + assert.is.equal 'facet: and -> long -> type', tostring Key 'facet: and -> long -> type' + assert.is.equal 'facet: and -> long -> type', tostring Key 'facet', 'and -> long -> type' + assert.is.equal 'facet: and -> long -> type', tostring Key 'facet: and -> long -> type' diff --git a/spec/stores_spec.moon b/spec/stores_spec.moon index 742d8c8..7fa2793 100644 --- a/spec/stores_spec.moon +++ b/spec/stores_spec.moon @@ -1,32 +1,4 @@ --- relative imports -_G.relative = do - _require = require - - (base, sub) -> - sub = sub or 0 - - for i=1, sub - base = base\match '^(.*)%.%w+$' - - (name, x) -> - if name == '.' - name = base - else if '.' == name\sub 1, 1 - name = base .. name - - _require name - -sort2 = (a, b) -> - {ax, ay}, {bx, by} = a, b - "#{ax}//#{ay}" < "#{bx}//#{by}" - -toseq = (iter) -> - with v = [x for x in iter] - table.sort v - -toseq2 = (iter) -> - with v = [{x, y} for x, y in iter] - table.sort v, sort2 +import toseq, toseq2 from require 'spec.test_util' test_store = (ts) -> randomize false diff --git a/spec/test_util.moon b/spec/test_util.moon new file mode 100644 index 0000000..b2ac026 --- /dev/null +++ b/spec/test_util.moon @@ -0,0 +1,34 @@ +-- relative imports +_G.relative = do + _require = require + + (base, sub) -> + sub = sub or 0 + + for i=1, sub + base = base\match '^(.*)%.%w+$' + + (name, x) -> + if name == '.' + name = base + else if '.' == name\sub 1, 1 + name = base .. name + + _require name + +sort2 = (a, b) -> + {ax, ay}, {bx, by} = a, b + "#{ax}//#{ay}" < "#{bx}//#{by}" + +toseq = (iter) -> + with v = [x for x in iter] + table.sort v + +toseq2 = (iter) -> + with v = [{x, y} for x, y in iter] + table.sort v, sort2 + +{ + :toseq + :toseq2 +} -- cgit v1.2.3 From 99cb9c082bd586fd478d5458178598f9b9fa0f25 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 11 Oct 2019 13:00:49 +0200 Subject: fix about section links --- root/about/text$markdown.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/root/about/text$markdown.md b/root/about/text$markdown.md index 9826089..7a2e6e7 100644 --- a/root/about/text$markdown.md +++ b/root/about/text$markdown.md @@ -4,8 +4,8 @@ i am s-ol bekic, a game designer and web developer currently based in cologne. i create experimental mixed-ware [games][games], [computer interfaces][mmmfs], [looping][loops] and [reactive][vjkit] animations and [other experiments.][other] -[games]: /games -[mmmfs]: /articles/mmmfs -[loops]: /projects/demoloops -[vjkit]: /projects/VJmidiKit -[other]: /projects +[games]: /games/ +[mmmfs]: /articles/mmmfs/ +[loops]: /projects/demoloops/ +[vjkit]: /projects/VJmidiKit/ +[other]: /projects/ -- cgit v1.2.3 From 8cdf5d4a363ba99a6356e7e1dfe0dfb39e6fb13e Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 11 Oct 2019 13:56:43 +0200 Subject: change ?interactive pseudofacet to text/html+interactive pseudo-type fix browser push/popstate --- build/server.moon | 53 ++++++++++++++++++++++++----------------------- mmm/mmmfs/browser.moon | 47 +++++++++++++++++++++++++---------------- mmm/mmmfs/fileder.moon | 5 +++-- mmm/mmmfs/stores/web.moon | 4 +--- spec/key_spec.moon | 10 +++++++++ 5 files changed, 70 insertions(+), 49 deletions(-) diff --git a/build/server.moon b/build/server.moon index 89cf1a6..ff138ee 100644 --- a/build/server.moon +++ b/build/server.moon @@ -47,28 +47,6 @@ class Server switch method when 'GET', 'HEAD' val = switch facet.name - when '?interactive' - export BROWSER - - root = Fileder @store - BROWSER = Browser root, path - render BROWSER\todom!, fileder, noview: true, scripts: " - " - when '?index', '?tree' -- serve fileder index -- '?index': one level deep @@ -81,7 +59,30 @@ class Server if not fileder\has_facet facet.name return 404, "facet '#{facet.name}' not found in fileder '#{path}'" - fileder\get facet + if facet.type == 'text/html+interactive' + export BROWSER + + root = Fileder @store + BROWSER = Browser root, path, facet.name + render BROWSER\todom!, fileder, noview: true, scripts: " + " + else + fileder\get facet if val 200, val @@ -100,7 +101,7 @@ class Server path_facet or= path path, facet = path_facet\match '(.*)/([^/]*)' - type or= 'text/html' + type or= 'text/html+interactive' type = type\match '%s*(.*)' facet = Key facet, type @@ -112,8 +113,8 @@ class Server res = headers.new! response_type = if status > 299 then 'text/plain' - else if facet then facet.type - else 'text/json' + else if facet.type == 'text/html+interactive' then 'text/html' + else facet.type res\append ':status', tostring status res\append 'content-type', response_type diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index 247e36a..a0c5541 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -40,13 +40,26 @@ for convert in *converts table.insert casts, convert class Browser - new: (@root, path, rehydrate=false) => + new: (@root, path, facet, rehydrate=false) => -- root fileder assert @root, 'root fileder is nil' -- active path @path = ReactiveVar path or '' + -- active fileder + -- (re)set every time @path changes + @active = @path\map @root\walk + + -- currently active facet + -- (re)set to default when @active changes + @facet = ReactiveVar Key facet, 'mmm/dom' + if MODE == 'CLIENT' + @active\subscribe (fileder) -> + return unless fileder + last = @facet and @facet\get! + @facet\set Key if last then last.type else 'mmm/dom' + -- update URL bar if MODE == 'CLIENT' logo = document\querySelector 'header h1 > a > svg' @@ -54,31 +67,29 @@ class Browser logo.classList\add 'spin' logo.parentElement.offsetWidth logo.classList\remove 'spin' - @path\subscribe (path) -> + + @facet\subscribe (facet) -> document.body.classList\add 'loading' spin! return if @skip - vis_path = path .. (if '/' == path\sub -1 then '' else '/') - window.history\pushState path, '', vis_path + + path = @path\get! + state = js.global\eval 'new Object()' + state.path = path + state.name = facet.name + state.type = facet.type + + window.history\pushState state, '', "#{path}/#{(Key facet.name, 'text/html+interactive')\tostring true}" window.onpopstate = (_, event) -> - if event.state and not event.state == js.null + state = event.state + if state != js.null @skip = true - @path\set event.state + @path\set state.path + @facet\set Key state.name, state.type @skip = nil - -- active fileder - -- (re)set every time @path changes - @active = @path\map @root\walk - - -- currently active facet - -- (re)set to default when @active changes - @facet = @active\map (fileder) -> - return unless fileder - last = @facet and @facet\get! - Key if last then last.type else 'mmm/dom' - -- whether inspect tab is active @inspect = ReactiveVar (MODE == 'CLIENT' and window.location.search\match '[?&]inspect') @@ -121,7 +132,7 @@ class Browser current = @facet\get! current = current and current.name - with select :onchange, disabled: not fileder + with select :onchange, disabled: not fileder, value: @facet\map (f) -> f and f.name has_main = fileder and fileder\has_facet '' \append option '(main)', value: '', disabled: not has_main, selected: current == '' if fileder diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index 8c89083..174f8b0 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -34,8 +34,9 @@ class Key assert ('string' == type @type), "type is not a string: '#{@type}'" -- format as a string (see constructor) - tostring: => - if @name == '' + -- in strict mode never omit name + tostring: (strict=false) => + if not strict and @name == '' @type else "#{@name}: #{@type}" diff --git a/mmm/mmmfs/stores/web.moon b/mmm/mmmfs/stores/web.moon index 082fea8..2eea45c 100644 --- a/mmm/mmmfs/stores/web.moon +++ b/mmm/mmmfs/stores/web.moon @@ -29,9 +29,7 @@ parse_json = do else val - (string) -> - print fix JSON\parse string - fix JSON\parse string + (string) -> fix JSON\parse string class WebStore extends Store new: (opts = {}) => diff --git a/spec/key_spec.moon b/spec/key_spec.moon index 9b7dde4..edd5ccf 100644 --- a/spec/key_spec.moon +++ b/spec/key_spec.moon @@ -56,3 +56,13 @@ describe "Key", -> assert.is.equal 'facet: and -> long -> type', tostring Key 'facet: and -> long -> type' assert.is.equal 'facet: and -> long -> type', tostring Key 'facet', 'and -> long -> type' assert.is.equal 'facet: and -> long -> type', tostring Key 'facet: and -> long -> type' + + it ":tostring formats the key", -> + assert.is.equal 'type/only', (Key 'type/only')\tostring! + assert.is.equal 'type/only', (Key '', 'type/only')\tostring! + assert.is.equal 'type/only', (Key ": type/only")\tostring! + + it ":tostring supports strict mode", -> + assert.is.equal ': type/only', (Key 'type/only')\tostring true + assert.is.equal ': type/only', (Key '', 'type/only')\tostring true + assert.is.equal ': type/only', (Key ": type/only")\tostring true -- cgit v1.2.3 From 07fc2ef73e372e7ce274f191d7a6202a74d0702f Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 11 Oct 2019 14:49:38 +0200 Subject: add ba_log entry 2019-10-10 --- .../mmmfs/ba_log/2019-10-10/text$markdown.md | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 root/articles/mmmfs/ba_log/2019-10-10/text$markdown.md diff --git a/root/articles/mmmfs/ba_log/2019-10-10/text$markdown.md b/root/articles/mmmfs/ba_log/2019-10-10/text$markdown.md new file mode 100644 index 0000000..bfecbeb --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-10-10/text$markdown.md @@ -0,0 +1,47 @@ +Today I moved the static resources needed by the web-frontend into the content of the mmmfs itself: +The server doesn't make an exception for static files anymore (as described in [a previous update][2019-10-08]), +but rather the files are just in a fileder called `static` now, and properly typed, here: + +- [`/static/style/`](/static/style/:%20text/html+interactive#inspect) +- [`/static/mmm/`](/static/mmm/:%20text/html+interactive#inspect) +- [`/static/fengari-web/`](/static/fengari-web/:%20text/html+interactive#inspect) + +This removed a big exception and left the server implementation much cleaner and shorter, as can be seen in the corresponding commit [`005cc9b`][005cc9b]. + +I also changed the route syntax introduced in [`2019-10-08`][2019-10-08] for getting the fileder index, +now instead of being hard-coded to return a JSON value at `?index` \[[`b36a1a6`][b36a1a6]\]. +`?index` is treated as a pseudo-facet that can be requested in different types, just like real facets. +I also added a second pseudo-facet `?tree`, which works like `?index`, except that it recurses and includes +all content below the current fileder, rather than just including the child-fileders. + +Here are some example links for viewing these: + +- [`/?index`](/?index) +- [`/articles/mmmfs/ba_log/?index: text/html`](/articles/mmmfs/ba_log/?index:%20text/html) + +Finally I added a third pseudo-facet called `?interactive` that renders the Inspector that the old page ran on, +allowing to inspect raw facets, and bringing back the navbar \[[`9ab2f0f`][9ab2f0f]\]. + +Now that there was a way to serve the Browser to the client again, I got to work on fixing it there. +This involved a bigger changes in the shared mmm internals: + +Up to this point, for each request to render a fileder, the server would load that fileder, +with all its facets and their values, as well as all children and their facets and children recursively. +That means that when the root fileder is rendered, currently 120MB of data have to be loaded from disk (or a database). +Now that the client can render content within the web browser again, that would be even worse due to the network delay. + +To solve this, the Fileder implementation now lazy-loads \[[`9632233`][9632233]\]. +When a Fileder is created, it initially knows only its path, but doesn't know which factes or children it contains. +As soon as that data is attempted to be accessed, the fileder loads in the list of its children and facets from the datastore. +The facet contents are loaded only when they are actually needed to fulfill a data request or conversion. + +With this need for optimization taken care of, I added a new datastore (`web`) \[[`91546d1`][91546d1]\], that can run on the client. +Instead of directly accessing a database or physical file system, like the `sql` and `fs` stores, the `web` store delegates all +requests to the server APIs I have been building, such as the new `?index` pseudo-facet. + +[2019-10-08]: /articles/mmmfs/ba_log/2019-10-08/ +[005cc9b]: https://git.s-ol.nu/mmm/commit/005cc9b3914128267017620984aee921999e173f/ +[b36a1a6]: https://git.s-ol.nu/mmm/commit/b36a1a6c61a6e8bff156ce4e2dc66fe8ed8cd95e/ +[9ab2f0f]: https://git.s-ol.nu/mmm/commit/9ab2f0fe3a1a043300536a057bafe5058d987d7f/ +[9632233]: https://git.s-ol.nu/mmm/commit/9632233c16a26f017c648faf36a6b26833e62f2e/ +[91546d1]: https://git.s-ol.nu/mmm/commit/91546d12919736b08567d7174bf1063cab0838f0/ -- cgit v1.2.3 From 4c16c503a66df20bff2d6a715dd78e4fa15f2da0 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 11 Oct 2019 15:21:48 +0200 Subject: fix #inspect links --- mmm/mmmfs/browser.moon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index a0c5541..7e768bd 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -91,7 +91,7 @@ class Browser @skip = nil -- whether inspect tab is active - @inspect = ReactiveVar (MODE == 'CLIENT' and window.location.search\match '[?&]inspect') + @inspect = ReactiveVar (MODE == 'CLIENT' and window.location.hash == '#inspect') -- retrieve or create the wrapper and main elements main = get_or_create 'div', 'browser-root', class: 'main view' -- cgit v1.2.3 From a295985741955fcc8835bd3b9b58d6eb3b3cbf36 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 11 Oct 2019 15:22:20 +0200 Subject: allow ?interactive with no main facet --- build/server.moon | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/build/server.moon b/build/server.moon index ff138ee..cb08131 100644 --- a/build/server.moon +++ b/build/server.moon @@ -55,10 +55,6 @@ class Server index = @store\get_index path, depth convert 'table', facet.type, index, fileder, facet.name else - -- fileder and facet given - if not fileder\has_facet facet.name - return 404, "facet '#{facet.name}' not found in fileder '#{path}'" - if facet.type == 'text/html+interactive' export BROWSER @@ -81,6 +77,8 @@ class Server BROWSER = browser.Browser(root, path, facet, true) end) " + else if not fileder\has_facet facet.name + 404, "facet '#{facet.name}' not found in fileder '#{path}'" else fileder\get facet -- cgit v1.2.3 From 4f87b432e04ffa4b7168c1c6f632086bb409c983 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 11 Oct 2019 15:33:23 +0200 Subject: add ba_log entry 2019-10-11 --- .../mmmfs/ba_log/2019-10-11/text$markdown.md | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 root/articles/mmmfs/ba_log/2019-10-11/text$markdown.md diff --git a/root/articles/mmmfs/ba_log/2019-10-11/text$markdown.md b/root/articles/mmmfs/ba_log/2019-10-11/text$markdown.md new file mode 100644 index 0000000..0b58c75 --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-10-11/text$markdown.md @@ -0,0 +1,30 @@ +Yesterday I got client-side access to the whole mmmfs tree to work via the new `web` datastore, +but the requests were still extremely inefficient. +This was because the organisation of the interface between the `Fileder` implementation and the datastore, +which required the Fileder to make two separate requests to `?index` to fetch its children and facets, +and also couldn't take advantage of the `?tree` pseudo-facet to bundle together multiple indexes in a single request. + +To fix this I added a new datastore method called `get_index` that returns both facet and child information \[[`e2a4257`][e2a4257]\] +The Fileder implementation now uses this method instead of asking individually for the two pieces of information +when lazy-loading fileder contents. +The `get_index` method can also be instructed to recursively load to a fixed depth. +A Fileder can also be instantiated using such a nested index, +which causes it to immediately preload up to the same depth without the need for fetching more data. +This allows some more optimizations, like having the client preload 3-levels deep when it launches, +which seems like a decent heuristic of the data actually required for most pages and minimizes load time. + +I also added some tests for the `Key` class that I use in many different places to represent facet names and types \[[`782d072`][782d072]\]]. + +The `?interactive` pseudo-facet from yesterday was changed to the `text/html+interactive` type instead \[[`8cdf5d4`][8cdf5d4]\]. +This was a bit of a tough decision, because it is a bit un-idiomatic: rendering the browser page still requires an exception in the browser. +In the end the motivation for the change was that it should be possible, +for user ergonomics, to link to the interactive view of a given facet of a given fileder. +With `?interactive` being a facet, it wasn't possible to specify the facet without jumping out of the adressing system. +With these updates on the other hand it is possible to link fo example: + +- to the main content of the root fileder, as an interactive view: [`/: text/html+interactive`](/:%20text/html+interactive) +- to the page title of the root fileder, as an interactive view: [`/title: text/html+interactive`](/title:%20text/html+interactive) + +[e2a4257]: https://git.s-ol.nu/mmm/commit/e2a4257fc05d37822df2b7bbe0f587645375edf2/ +[782d072]: https://git.s-ol.nu/mmm/commit/782d0725f3f29eaa7d4a12213fb00c6643795348/ +[8cdf5d4]: https://git.s-ol.nu/mmm/commit/8cdf5d4a363ba99a6356e7e1dfe0dfb39e6fb13e/ -- cgit v1.2.3 From 88f4fb03433e627455f0f7a9e72058fa3c06008c Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 11 Oct 2019 15:36:06 +0200 Subject: temporarily fix moonscript in client --- mmm/mmmfs/fileder.moon | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index 174f8b0..0d01a5e 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -158,6 +158,11 @@ class Fileder key = Key key @facet_keys[key] = key + if MODE == 'CLIENT' and key.type\match 'text/moonscript' + -- @TODO: this doesn't belong here + copy = Key key.name, key.type\gsub 'text/moonscript', 'text/lua' + @facet_keys[copy] = copy + _, name = dir_base @path @facets['name: alpha'] = name -- cgit v1.2.3 From 6c3836ec3553819a0dda95efd0855910682fc518 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 11 Oct 2019 16:04:36 +0200 Subject: fix browser nav issues, fs default sorting --- .gitignore | 2 +- Tupfile | 2 +- build/server.moon | 7 ++- mmm/mmmfs/browser.moon | 18 +++---- mmm/mmmfs/converts.moon | 56 +++++++++++++++------- mmm/mmmfs/fileder.moon | 3 ++ mmm/mmmfs/layout.moon | 14 +++--- mmm/mmmfs/stores/fs.moon | 18 +++++-- mmm/mmmfs/stores/web.moon | 6 +-- .../mmmfs/ba_log/2019-10-10/text$markdown.md | 7 ++- .../text$moonscript -> mmm$component.moon | 2 +- root/static/fengari-web/application$javascript.js | 8 ---- root/static/fengari-web/map: application$json | 1 - root/static/fengari-web/map: text$json | 1 + root/static/fengari-web/text$javascript.js | 8 ++++ .../highlight-pack/application$javascript.js | 2 - root/static/highlight-pack/text$javascript.js | 2 + 17 files changed, 91 insertions(+), 66 deletions(-) delete mode 100644 root/static/fengari-web/application$javascript.js delete mode 100644 root/static/fengari-web/map: application$json create mode 100644 root/static/fengari-web/map: text$json create mode 100644 root/static/fengari-web/text$javascript.js delete mode 100644 root/static/highlight-pack/application$javascript.js create mode 100644 root/static/highlight-pack/text$javascript.js diff --git a/.gitignore b/.gitignore index 06ed155..f7b8c9a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ db.sqlite3 root/static/style/text$css.css -root/static/mmm/application$lua.lua +root/static/mmm/text$lua.lua ##### TUP GITIGNORE ##### ##### Lines below automatically generated by Tup. ##### Do not edit. diff --git a/Tupfile b/Tupfile index 0d771d1..9e5cbac 100644 --- a/Tupfile +++ b/Tupfile @@ -6,4 +6,4 @@ include_rules : scss/main.scss |> !sassc |> root/static/style/text$css.css # bundle for client loading -: mmm/.bundle.lua | |> ^ WRAP %d^ moon &(build)/bundle_module.moon '%o' --wrap %f |> root/static/mmm/application$lua.lua +: mmm/.bundle.lua | |> ^ WRAP %d^ moon &(build)/bundle_module.moon '%o' --wrap %f |> root/static/mmm/text$lua.lua diff --git a/build/server.moon b/build/server.moon index cb08131..72b5ffd 100644 --- a/build/server.moon +++ b/build/server.moon @@ -34,7 +34,7 @@ class Server assert @server\listen! _, ip, port = @server\localname! - print "SV", "running at #{ip}:#{port}" + print "[#{@@__name}]", "running at #{ip}:#{port}" assert @server\loop! handle: (method, path, facet) => @@ -61,7 +61,7 @@ class Server root = Fileder @store BROWSER = Browser root, path, facet.name render BROWSER\todom!, fileder, noview: true, scripts: " - - - - - - - + + + + + + + ]] buf ..= opts.scripts diff --git a/mmm/mmmfs/stores/fs.moon b/mmm/mmmfs/stores/fs.moon index 5167668..1300d55 100644 --- a/mmm/mmmfs/stores/fs.moon +++ b/mmm/mmmfs/stores/fs.moon @@ -22,12 +22,19 @@ class FSStore extends Store -- fileders list_fileders_in: (path='') => + paths = for entry_name in lfs.dir @root .. path + continue if '.' == entry_name\sub 1, 1 + entry_path = @root .. "#{path}/#{entry_name}" + if 'directory' ~= lfs.attributes entry_path, 'mode' + continue + + "#{path}/#{entry_name}" + + table.sort paths coroutine.wrap -> - for entry_name in lfs.dir @root .. path - continue if '.' == entry_name\sub 1, 1 - entry_path = @root .. "#{path}/#{entry_name}" - if 'directory' == lfs.attributes entry_path, 'mode' - coroutine.yield "#{path}/#{entry_name}" + -- @TODO: respect $order + for path in *paths + coroutine.yield path create_fileder: (parent, name) => @log "creating fileder #{path}" @@ -68,6 +75,7 @@ class FSStore extends Store coroutine.wrap -> for entry_name in lfs.dir @root .. path entry_path = "#{@root .. path}/#{entry_name}" + continue if entry_name == '$order' if 'file' == lfs.attributes entry_path, 'mode' entry_name = (entry_name\match '(.*)%.%w+') or entry_name entry_name = entry_name\gsub '%$', '/' diff --git a/mmm/mmmfs/stores/web.moon b/mmm/mmmfs/stores/web.moon index 2eea45c..f3b60c7 100644 --- a/mmm/mmmfs/stores/web.moon +++ b/mmm/mmmfs/stores/web.moon @@ -45,13 +45,13 @@ class WebStore extends Store get_index: (path='', depth=1) => pseudo = if depth > 1 or depth < 0 '?tree' else '?index' - json = fetch "#{@host .. path}/#{pseudo}: application/json" + json = fetch "#{@host .. path}/#{pseudo}: text/json" parse_json json -- fileders list_fileders_in: (path='') => coroutine.wrap -> - json = fetch "#{@host .. path}/?index: application/json" + json = fetch "#{@host .. path}/?index: text/json" index = parse_json json for child in js.of index.children coroutine.yield child.path @@ -75,7 +75,7 @@ class WebStore extends Store -- facets list_facets: (path) => coroutine.wrap -> - json = fetch "#{@host .. path}/?index: application/json" + json = fetch "#{@host .. path}/?index: text/json" index = JSON\parse json for facet in js.of index.facets coroutine.yield facet.name, facet.type diff --git a/root/articles/mmmfs/ba_log/2019-10-10/text$markdown.md b/root/articles/mmmfs/ba_log/2019-10-10/text$markdown.md index bfecbeb..549ea99 100644 --- a/root/articles/mmmfs/ba_log/2019-10-10/text$markdown.md +++ b/root/articles/mmmfs/ba_log/2019-10-10/text$markdown.md @@ -2,9 +2,8 @@ Today I moved the static resources needed by the web-frontend into the content o The server doesn't make an exception for static files anymore (as described in [a previous update][2019-10-08]), but rather the files are just in a fileder called `static` now, and properly typed, here: -- [`/static/style/`](/static/style/:%20text/html+interactive#inspect) -- [`/static/mmm/`](/static/mmm/:%20text/html+interactive#inspect) -- [`/static/fengari-web/`](/static/fengari-web/:%20text/html+interactive#inspect) +- [/static/style/](/static/style/:%20text/html+interactive) +- [/static/mmm/](/static/mmm/:%20text/html+interactive) This removed a big exception and left the server implementation much cleaner and shorter, as can be seen in the corresponding commit [`005cc9b`][005cc9b]. @@ -16,7 +15,7 @@ all content below the current fileder, rather than just including the child-file Here are some example links for viewing these: -- [`/?index`](/?index) +- [`/?index: text/html`](/?index:%20text/html) - [`/articles/mmmfs/ba_log/?index: text/html`](/articles/mmmfs/ba_log/?index:%20text/html) Finally I added a third pseudo-facet called `?interactive` that renders the Inspector that the old page ran on, diff --git a/root/articles/realities/text$moonscript -> mmm$component.moon b/root/articles/realities/text$moonscript -> mmm$component.moon index 7689dbb..a7dc365 100644 --- a/root/articles/realities/text$moonscript -> mmm$component.moon +++ b/root/articles/realities/text$moonscript -> mmm$component.moon @@ -24,7 +24,7 @@ if MODE == 'SERVER' render: => rplc = with div id: @id, :style \append '(diagram goes here)' - -- \append "",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"tag",b:"",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",t={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/},{b:/\(/,e:/\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",i:/:/,c:[{cN:"keyword",b:/\w+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:c,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,t]}]}});hljs.registerLanguage("javascript",function(e){var r="[A-Za-z$_][0-9A-Za-z$_]*",t={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},a={cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},n={cN:"subst",b:"\\$\\{",e:"\\}",k:t,c:[]},c={cN:"string",b:"`",e:"`",c:[e.BE,n]};n.c=[e.ASM,e.QSM,c,a,e.RM];var s=n.c.concat([e.CBCM,e.CLCM]);return{aliases:["js","jsx"],k:t,c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,c,e.CLCM,e.CBCM,a,{b:/[{,]\s*/,r:0,c:[{b:r+"\\s*:",rB:!0,r:0,c:[{cN:"attr",b:r,r:0}]}]},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+r+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:r},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:s}]}]},{b://,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:[{b:/<\w+\s*\/>/,skip:!0},"self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:r}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:s}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}});hljs.registerLanguage("markdown",function(e){return{aliases:["md","mkdown","mkd"],c:[{cN:"section",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"quote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"^```w*s*$",e:"^```s*$"},{b:"`.+?`"},{b:"^( {4}| )",e:"$",r:0}]},{b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].*?[\\)\\]]",rB:!0,c:[{cN:"string",b:"\\[",e:"\\]",eB:!0,rE:!0,r:0},{cN:"link",b:"\\]\\(",e:"\\)",eB:!0,eE:!0},{cN:"symbol",b:"\\]\\[",e:"\\]",eB:!0,eE:!0}],r:10},{b:/^\[[^\n]+\]:/,rB:!0,c:[{cN:"symbol",b:/\[/,e:/\]/,eB:!0,eE:!0},{cN:"link",b:/:\s*/,e:/$/,eB:!0}]}]}}); \ No newline at end of file diff --git a/root/static/highlight-pack/text$javascript.js b/root/static/highlight-pack/text$javascript.js new file mode 100644 index 0000000..0a64756 --- /dev/null +++ b/root/static/highlight-pack/text$javascript.js @@ -0,0 +1,2 @@ +/*! highlight.js v9.13.1 | BSD3 License | git.io/hljslicense */ +!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/g,"&").replace(//g,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=M.exec(o))return w(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||w(i))return i}function o(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function c(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function u(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function c(e){l+=""}function u(e){("start"===e.event?o:c)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substring(s,g[0].offset)),s=g[0].offset,g===e){f.reverse().forEach(c);do u(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===s);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),u(g.splice(0,1)[0])}return l+n(a.substr(s))}function s(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(n){return o(e,{v:null},n)})),e.cached_variants||e.eW&&[o(e)]||[e]}function l(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):B(a.k).forEach(function(e){c(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.endSameAsBegin&&(a.e=a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]),a.c=Array.prototype.concat.apply([],a.c.map(function(e){return s("self"===e?a:e)})),a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var u=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=u.length?t(u.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e){return new RegExp(e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")}function c(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t].endSameAsBegin&&(n.c[t].eR=o(n.c[t].bR.exec(e)[0])),n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function s(e,n){return!a&&r(n.iR,e)}function p(e,n){var t=R.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function d(e,n,t,r){var a=r?"":j.classPrefix,i='',i+n+o}function h(){var e,t,r,a;if(!E.k)return n(k);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(k);r;)a+=n(k.substring(t,r.index)),e=p(E,r),e?(M+=e[1],a+=d(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(k);return a+n(k.substr(t))}function b(){var e="string"==typeof E.sL;if(e&&!L[E.sL])return n(k);var t=e?f(E.sL,k,!0,B[E.sL]):g(k,E.sL.length?E.sL:void 0);return E.r>0&&(M+=t.r),e&&(B[E.sL]=t.top),d(t.language,t.value,!1,!0)}function v(){y+=null!=E.sL?b():h(),k=""}function m(e){y+=e.cN?d(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function N(e,n){if(k+=e,null==n)return v(),0;var t=c(n,E);if(t)return t.skip?k+=n:(t.eB&&(k+=n),v(),t.rB||t.eB||(k=n)),m(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?k+=n:(a.rE||a.eE||(k+=n),v(),a.eE&&(k=n));do E.cN&&(y+=I),E.skip||E.sL||(M+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&(r.endSameAsBegin&&(r.starts.eR=r.eR),m(r.starts,"")),a.rE?0:n.length}if(s(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return k+=n,n.length||1}var R=w(e);if(!R)throw new Error('Unknown language: "'+e+'"');l(R);var x,E=i||R,B={},y="";for(x=E;x!==R;x=x.parent)x.cN&&(y=d(x.cN,"",!0)+y);var k="",M=0;try{for(var C,A,S=0;;){if(E.t.lastIndex=S,C=E.t.exec(t),!C)break;A=N(t.substring(S,C.index),C[0]),S=C.index+A}for(N(t.substr(S)),x=E;x.parent;x=x.parent)x.cN&&(y+=I);return{r:M,value:y,language:e,top:E}}catch(O){if(O.message&&-1!==O.message.indexOf("Illegal"))return{r:0,value:n(t)};throw O}}function g(e,t){t=t||j.languages||B(L);var r={r:0,value:n(e)},a=r;return t.filter(w).filter(x).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function p(e){return j.tabReplace||j.useBR?e.replace(C,function(e,n){return j.useBR&&"\n"===e?"
":j.tabReplace?n.replace(/\t/g,j.tabReplace):""}):e}function d(e,n,t){var r=n?y[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function h(e){var n,t,r,o,s,l=i(e);a(l)||(j.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):n=e,s=n.textContent,r=l?f(l,s,!0):g(s),t=c(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=u(t,c(o),s)),r.value=p(r.value),e.innerHTML=r.value,e.className=d(e.className,l,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function b(e){j=o(j,e)}function v(){if(!v.called){v.called=!0;var e=document.querySelectorAll("pre code");E.forEach.call(e,h)}}function m(){addEventListener("DOMContentLoaded",v,!1),addEventListener("load",v,!1)}function N(n,t){var r=L[n]=t(e);r.aliases&&r.aliases.forEach(function(e){y[e]=n})}function R(){return B(L)}function w(e){return e=(e||"").toLowerCase(),L[e]||L[y[e]]}function x(e){var n=w(e);return n&&!n.disableAutodetect}var E=[],B=Object.keys,L={},y={},k=/^(no-?highlight|plain|text)$/i,M=/\blang(?:uage)?-([\w-]+)\b/i,C=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,I="
",j={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=f,e.highlightAuto=g,e.fixMarkup=p,e.highlightBlock=h,e.configure=b,e.initHighlighting=v,e.initHighlightingOnLoad=m,e.registerLanguage=N,e.listLanguages=R,e.getLanguage=w,e.autoDetection=x,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("moonscript",function(e){var t={keyword:"if then not for in while do return else elseif break continue switch and or unless when class extends super local import export from using",literal:"true false nil",built_in:"_G _VERSION assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall coroutine debug io math os package string table"},r="[A-Za-z$_][0-9A-Za-z$_]*",s={cN:"subst",b:/#\{/,e:/}/,k:t},a=[e.inherit(e.CNM,{starts:{e:"(\\s*/)?",r:0}}),{cN:"string",v:[{b:/'/,e:/'/,c:[e.BE]},{b:/"/,e:/"/,c:[e.BE,s]}]},{cN:"built_in",b:"@__"+e.IR},{b:"@"+e.IR},{b:e.IR+"\\\\"+e.IR}];s.c=a;var c=e.inherit(e.TM,{b:r}),n="(\\(.*\\))?\\s*\\B[-=]>",i={cN:"params",b:"\\([^\\(]",rB:!0,c:[{b:/\(/,e:/\)/,k:t,c:["self"].concat(a)}]};return{aliases:["moon"],k:t,i:/\/\*/,c:a.concat([e.C("--","$"),{cN:"function",b:"^\\s*"+r+"\\s*=\\s*"+n,e:"[-=]>",rB:!0,c:[c,i]},{b:/[\(,:=]\s*/,r:0,c:[{cN:"function",b:n,e:"[-=]>",rB:!0,c:[i]}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:!0,i:/[:="\[\]]/,c:[c]},c]},{cN:"name",b:r+":",e:":",rB:!0,rE:!0,r:0}])}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/\b-?[a-z\._]+\b/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage("lua",function(e){var t="\\[=*\\[",a="\\]=*\\]",r={b:t,e:a,c:["self"]},n=[e.C("--(?!"+t+")","$"),e.C("--"+t,a,{c:[r],r:10})];return{l:e.UIR,k:{literal:"true false nil",keyword:"and break do else elseif end for goto if in local not or repeat return then until while",built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstringmodule next pairs pcall print rawequal rawget rawset require select setfenvsetmetatable tonumber tostring type unpack xpcall arg selfcoroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"},c:n.concat([{cN:"function",bK:"function",e:"\\)",c:[e.inherit(e.TM,{b:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{cN:"params",b:"\\(",eW:!0,c:n}].concat(n)},e.CNM,e.ASM,e.QSM,{cN:"string",b:t,e:a,c:[r],r:5}])}});hljs.registerLanguage("xml",function(s){var e="[A-Za-z0-9\\._:-]+",t={eW:!0,i:/`]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist"],cI:!0,c:[{cN:"meta",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},s.C("",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"meta",b:/<\?xml/,e:/\?>/,r:10},{b:/<\?(php)?/,e:/\?>/,sL:"php",c:[{b:"/\\*",e:"\\*/",skip:!0},{b:'b"',e:'"',skip:!0},{b:"b'",e:"'",skip:!0},s.inherit(s.ASM,{i:null,cN:null,c:null,skip:!0}),s.inherit(s.QSM,{i:null,cN:null,c:null,skip:!0})]},{cN:"tag",b:"|$)",e:">",k:{name:"style"},c:[t],starts:{e:"",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"|$)",e:">",k:{name:"script"},c:[t],starts:{e:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"tag",b:"",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",t={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/},{b:/\(/,e:/\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",i:/:/,c:[{cN:"keyword",b:/\w+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:c,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,t]}]}});hljs.registerLanguage("javascript",function(e){var r="[A-Za-z$_][0-9A-Za-z$_]*",t={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},a={cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},n={cN:"subst",b:"\\$\\{",e:"\\}",k:t,c:[]},c={cN:"string",b:"`",e:"`",c:[e.BE,n]};n.c=[e.ASM,e.QSM,c,a,e.RM];var s=n.c.concat([e.CBCM,e.CLCM]);return{aliases:["js","jsx"],k:t,c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,c,e.CLCM,e.CBCM,a,{b:/[{,]\s*/,r:0,c:[{b:r+"\\s*:",rB:!0,r:0,c:[{cN:"attr",b:r,r:0}]}]},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+r+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:r},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:s}]}]},{b://,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:[{b:/<\w+\s*\/>/,skip:!0},"self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:r}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:s}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}});hljs.registerLanguage("markdown",function(e){return{aliases:["md","mkdown","mkd"],c:[{cN:"section",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"quote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"^```w*s*$",e:"^```s*$"},{b:"`.+?`"},{b:"^( {4}| )",e:"$",r:0}]},{b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].*?[\\)\\]]",rB:!0,c:[{cN:"string",b:"\\[",e:"\\]",eB:!0,rE:!0,r:0},{cN:"link",b:"\\]\\(",e:"\\)",eB:!0,eE:!0},{cN:"symbol",b:"\\]\\[",e:"\\]",eB:!0,eE:!0}],r:10},{b:/^\[[^\n]+\]:/,rB:!0,c:[{cN:"symbol",b:/\[/,e:/\]/,eB:!0,eE:!0},{cN:"link",b:/:\s*/,e:/$/,eB:!0}]}]}}); \ No newline at end of file -- cgit v1.2.3 From deb21aa43fe8bf11eb276803973b272913b7e716 Mon Sep 17 00:00:00 2001 From: s-ol Date: Mon, 14 Oct 2019 15:07:27 +0200 Subject: new type/pathfinding algorithm --- mmm/mmmfs/browser.moon | 5 ++- mmm/mmmfs/conversion.moon | 78 +++++++++++++++++++++++++++-------------- mmm/mmmfs/converts.moon | 23 +++++++++++++ mmm/mmmfs/fileder.moon | 12 +++++-- mmm/mmmfs/queue.moon | 66 +++++++++++++++++++++++++++++++++++ spec/queue_spec.moon | 88 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 244 insertions(+), 28 deletions(-) create mode 100644 mmm/mmmfs/queue.moon create mode 100644 spec/queue_spec.moon diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index cdeba30..f872ed9 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -1,9 +1,10 @@ require = relative ..., 1 import Key from require '.fileder' -import converts, get_conversions, apply_conversions from require '.conversion' +import get_conversions, apply_conversions from require '.conversion' import ReactiveVar, get_or_create, text, elements, tohtml from require 'mmm.component' import pre, div, nav, span, button, a, code, select, option from elements import languages from require 'mmm.highlighting' +converts = require '.converts' keep = (var) -> last = var\get! @@ -15,6 +16,7 @@ code_cast = (lang) -> { inp: "text/#{lang}.*", out: 'mmm/dom', + cost: 0 transform: (val) => languages[lang] val } @@ -28,6 +30,7 @@ casts = { { inp: 'URL.*' out: 'mmm/dom' + cost: 0 transform: (href) => span a (code href), :href } } diff --git a/mmm/mmmfs/conversion.moon b/mmm/mmmfs/conversion.moon index 31cbf5e..4b47bba 100644 --- a/mmm/mmmfs/conversion.moon +++ b/mmm/mmmfs/conversion.moon @@ -1,16 +1,19 @@ require = relative ..., 1 -converts = require '.converts' +base_converts = require '.converts' +import Queue from require '.queue' count = (base, pattern='->') -> select 2, base\gsub pattern, '' escape_pattern = (inp) -> "^#{inp\gsub '([^%w])', '%%%1'}$" escape_inp = (inp) -> "^#{inp\gsub '([-/])', '%%%1'}$" +local print_conversions + -- attempt to find a conversion path from 'have' to 'want' -- * have - start type string or list of type strings -- * want - stop type pattern -- * limit - limit conversion amount -- returns a list of conversion steps -get_conversions = (want, have, _converts=converts, limit=5) -> +get_conversions = (want, have, converts=base_converts, limit=5) -> assert have, 'need starting type(s)' if 'string' == type have @@ -19,29 +22,55 @@ get_conversions = (want, have, _converts=converts, limit=5) -> assert #have > 0, 'need starting type(s) (list was empty)' want = escape_pattern want - iterations = limit + math.max table.unpack [count type for type in *have] - have = [{ :start, rest: start, conversions: {} } for start in *have] - - for i=1, iterations - next_have, c = {}, 1 - for { :start, :rest, :conversions } in *have - if rest\match want - return conversions, start + limit = limit + 3 * math.max table.unpack [count type for type in *have] + + had = {} + queue = Queue! + for start in *have + return {}, start if want\match start + queue\add { :start, rest: start, conversions: {} }, 0, start + + best = Queue! + + while true + entry, cost = queue\pop! + if not entry or cost > limit + break + + { :start, :rest, :conversions } = entry + had[rest] = true + for convert in *converts + inp = escape_inp convert.inp + continue unless rest\match inp + result = rest\gsub inp, convert.out + continue unless result + continue if had[result] + + next_entry = { + :start + rest: result + cost: cost + convert.cost + conversions: { { :convert, from: rest, to: result }, table.unpack conversions } + } + + if result\match want + best\add next_entry, next_entry.cost else - for convert in *_converts - inp = escape_inp convert.inp - continue unless rest\match inp - result = rest\gsub inp, convert.out - if result - next_have[c] = { - :start, - rest: result, - conversions: { { :convert, from: rest, to: result }, table.unpack conversions } - } - c += 1 - - have = next_have - return unless #have > 0 + queue\add next_entry, next_entry.cost, result + + + if solution = best\pop! + -- print "BEST: (#{solution.cost})" + -- print_conversions solution.conversions + solution.conversions, solution.start if solution + +-- stringify conversions for debugging +-- * conversions - conversions from get_conversions +print_conversions = (conversions) -> + print "converting:" + for i=#conversions,1,-1 + step = conversions[i] + print "- #{step.from} -> #{step.to} (#{step.convert.cost})" -- apply transforms for conversion path sequentially -- * conversions - conversions from get_conversions @@ -73,7 +102,6 @@ convert = (have, want, value, ...) -> apply_conversions conversions, value, ... { - :converts :get_conversions :apply_conversions :convert diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon index 9276c33..e4a6ddf 100644 --- a/mmm/mmmfs/converts.moon +++ b/mmm/mmmfs/converts.moon @@ -30,6 +30,7 @@ code_hl = (lang) -> { inp: "text/#{lang}", out: 'mmm/dom', + cost: 5 transform: (val) => pre languages[lang] val } @@ -42,16 +43,19 @@ converts = { { inp: 'fn -> (.+)', out: '%1', + cost: 1 transform: (val, fileder) => val fileder } { inp: 'mmm/component', out: 'mmm/dom', + const: 3 transform: single tohtml } { inp: 'mmm/dom', out: 'text/html+frag', + cost: 3 transform: (node) => if MODE == 'SERVER' then node else node.outerHTML } { @@ -59,11 +63,13 @@ converts = { -- @TODO: this doesn't feel right... maybe mmm/dom has to go? inp: 'mmm/dom', out: 'text/html', + cost: 3 transform: (html, fileder) => render html, fileder } { inp: 'text/html%+frag', out: 'mmm/dom', + cost: 1 transform: if MODE == 'SERVER' (html, fileder) => html = html\gsub '(.-)', (attrs, text) -> @@ -138,11 +144,13 @@ converts = { { inp: 'text/lua -> (.+)', out: '%1', + cost: 0.5 transform: loadwith load or loadstring } { inp: 'mmm/tpl -> (.+)', out: '%1', + cost: 1 transform: (source, fileder) => source\gsub '{{(.-)}}', (expr) -> path, facet = expr\match '^([%w%-_%./]*)%+(.*)' @@ -153,6 +161,7 @@ converts = { { inp: 'time/iso8601-date', out: 'time/unix', + cost: 0.5 transform: (val) => year, _, month, day = val\match '^%s*(%d%d%d%d)(%-?)([01]%d)%2([0-3]%d)%s*$' assert year, "failed to parse ISO 8601 date: '#{val}'" @@ -161,6 +170,7 @@ converts = { { inp: 'URL -> twitter/tweet', out: 'mmm/dom', + cost: 1 transform: (href) => id = assert (href\match 'twitter.com/[^/]-/status/(%d*)'), "couldn't parse twitter/tweet URL: '#{href}'" if MODE == 'CLIENT' @@ -176,6 +186,7 @@ converts = { { inp: 'URL -> youtube/video', out: 'mmm/dom', + cost: 1 transform: (link) => id = link\match 'youtu%.be/([^/]+)' id or= link\match 'youtube.com/watch.*[?&]v=([^&]+)' @@ -196,11 +207,13 @@ converts = { { inp: 'URL -> image/.+', out: 'mmm/dom', + cost: 1 transform: (src, fileder) => img :src } { inp: 'URL -> video/.+', out: 'mmm/dom', + cost: 1 transform: (src) => -- @TODO: add parsed MIME type video (source :src), controls: true, loop: true @@ -208,11 +221,13 @@ converts = { { inp: 'text/plain', out: 'mmm/dom', + cost: 2 transform: (val) => span val } { inp: 'alpha', out: 'mmm/dom', + cost: 2 transform: single code } -- this one needs a higher cost @@ -224,11 +239,13 @@ converts = { { inp: '(.+)', out: 'URL -> %1', + cost: 10 transform: (_, fileder, key) => "#{fileder.path}/#{key.name}:#{@from}" } { inp: 'table', out: 'text/json', + cost: 2 transform: do tojson = (obj) -> switch type obj @@ -253,6 +270,7 @@ converts = { { inp: 'table', out: 'mmm/dom', + cost: 5 transform: do deep_tostring = (tbl, space='') -> buf = space .. tostring tbl @@ -281,18 +299,21 @@ if MODE == 'SERVER' table.insert converts, { inp: 'text/moonscript -> (.+)', out: '%1', + cost: 1 transform: loadwith moon.load or moon.loadstring } table.insert converts, { inp: 'text/moonscript -> (.+)', out: 'text/lua -> %1', + cost: 2 transform: single moon.to_lua } else table.insert converts, { inp: 'text/javascript -> (.+)', out: '%1', + cost: 1 transform: (source) => f = js.new window.Function, source f! @@ -315,12 +336,14 @@ do table.insert converts, { inp: 'text/markdown', out: 'text/html+frag', + cost: 1 transform: (md) => "
#{markdown md}
" } table.insert converts, { inp: 'text/markdown%+span', out: 'mmm/dom', + cost: 1 transform: if MODE == 'SERVER' (source) => html = markdown source diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index cf517a1..cdfc649 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -96,7 +96,7 @@ class Fileder __index: (t, k) -> canonical = rawget t, tostring k - canonical or= Key k + -- canonical or= Key k canonical __newindex: (t, k, v) -> @@ -109,6 +109,7 @@ class Fileder -- get canonical Key instance k = @facet_keys[k] + return unless k -- if cached, return if v = rawget t, k @@ -129,6 +130,7 @@ class Fileder __newindex: (t, k, v) -> -- get canonical Key instance k = @facet_keys[k] + return unless k rawset t, k, v @@ -167,7 +169,9 @@ class Fileder @facet_keys[copy] = copy _, name = dir_base @path - @facets['name: alpha'] = name + name_key = Key 'name: alpha' + @facet_keys[name_key] = name_key + @facets[name_key] = name -- recursively walk to and return the fileder with @path == path -- * path - the path to walk to @@ -255,6 +259,10 @@ class Fileder get: (...) => want = Key ... + -- return directly if present + if val = @facets[want] + return val, want + -- find matching key and shortest conversion path key, conversions = @find want diff --git a/mmm/mmmfs/queue.moon b/mmm/mmmfs/queue.moon new file mode 100644 index 0000000..f90d41b --- /dev/null +++ b/mmm/mmmfs/queue.moon @@ -0,0 +1,66 @@ +-- a priority queue with an index +-- only one element with a given key may exist at a time +-- when an element with an existing key is added, +-- the element with lower priority survives. +class Queue + new: => + @values = {} + @index = {} + + -- add a value with a given priority to the queue + -- if no key is specified, assume the element is uniq + add: (value, priority, key) => + entry = { :value, :key, :priority } + + if key + if old_entry = @index[key] + -- already have an entry for this key + -- if it is lower priority, we leave it there and do nothing + if old_entry.priority < priority + return + + -- otherwise we remove the old one and continue as normal + -- find the index of the old entry + local i + for ii, entry in ipairs @values + if entry == old_entry + i = ii + break + + -- remove it + table.remove @values, i + + -- store this entry in the index + @index[key] = entry + + -- store lowest priority last + for i, v in ipairs @values + if v.priority < priority + -- i is the first key that is lower, + -- we want to insert right before it + table.insert @values, i, entry + return + + -- couldn't find a key with a lower priority, + -- so insert at the end + table.insert @values, entry + + peek: => + entry = @values[#@values] + if entry + { :value, :priority, :key } = entry + @index[key] = nil if key + value, priority + + pop: => + entry = table.remove @values + if entry + { :value, :priority, :key } = entry + @index[key] = nil if key + value, priority + + -- iterator, yields (value, priority), low priority first + poll: => @.pop, @ +{ + :Queue +} diff --git a/spec/queue_spec.moon b/spec/queue_spec.moon new file mode 100644 index 0000000..d095398 --- /dev/null +++ b/spec/queue_spec.moon @@ -0,0 +1,88 @@ +import Queue from require 'mmm.mmmfs.queue' + +describe "Queue", -> + it "stores things", -> + queue = Queue! + queue\add "test", 1 + queue\add "toast", 2 + queue\add "spice", 3 + + assert.is.equal "test", queue\pop! + assert.is.equal "toast", queue\pop! + assert.is.equal "spice", queue\pop! + assert.is.nil queue\pop! + + it "doesnt care about the order", -> + queue = Queue! + queue\add "spice", 3 + queue\add "test", 1 + queue\add "toast", 2 + + assert.is.equal "test", queue\pop! + assert.is.equal "toast", queue\pop! + + queue\add "pepper", 5 + queue\add "salt", .5 + assert.is.equal "salt", queue\pop! + assert.is.equal "spice", queue\pop! + assert.is.equal "pepper", queue\pop! + + it "can be peeked", -> + queue = Queue! + queue\add "spice", 3 + queue\add "test", 1 + queue\add "toast", 2 + + assert.is.equal "test", queue\peek! + assert.is.equal "test", queue\pop! + queue\pop! + + queue\add "pepper", 5 + queue\add "salt", .5 + + assert.is.equal "salt", queue\peek! + queue\pop! + queue\pop! + + assert.is.equal "pepper", queue\peek! + queue\pop! + + assert.is.nil queue\peek! + + it "keeps keys in an index", -> + queue = Queue! + queue\add "test", 1, 'test' + queue\add "toast", 2, 'toast' + queue\add "spice", 3, 'spice' + + assert.is.equal "test", queue\peek! + queue\add "spice2", .5, 'spice' + assert.is.equal "spice2", queue\pop! + assert.is.equal "test", queue\pop! + + queue\add "bad toast", 5, 'toast' + assert.is.equal "toast", queue\pop! + assert.is.nil queue\pop! + + it "provides an iterator", -> + queue = Queue! + queue\add "test", 1 + queue\add "spice", 3 + queue\add "toast", 2 + + expect = {'test', 'toast', 'late', 'spice'} + expect_next = 1 + report = spy.new (v, i) -> + assert.is.equal expect[expect_next], v + expect_next += 1 + + for value, prio in queue\poll! + report value, prio + + if value == 'toast' + queue\add "late", 0.5 + + assert.stub(report).was.called_with('test', 1) + assert.stub(report).was.called_with('toast', 2) + assert.stub(report).was.called_with('spice', 3) + assert.stub(report).was.called_with('late', 0.5) -- cgit v1.2.3 From 75b3bc0b385ea1fb9eda3e29e5b0414b91015356 Mon Sep 17 00:00:00 2001 From: s-ol Date: Mon, 14 Oct 2019 15:31:30 +0200 Subject: add ba_log entry 2019-10-14 --- .../mmmfs/ba_log/2019-10-14/text$markdown.md | 101 +++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 root/articles/mmmfs/ba_log/2019-10-14/text$markdown.md diff --git a/root/articles/mmmfs/ba_log/2019-10-14/text$markdown.md b/root/articles/mmmfs/ba_log/2019-10-14/text$markdown.md new file mode 100644 index 0000000..e42f8be --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-10-14/text$markdown.md @@ -0,0 +1,101 @@ +I finally added a better type-conversion-path-finding algorithm \[[`deb21aa`][deb21aa]\]. +The old algorithm only took into consideration how many steps it took to get from type A (stored on disk) to type B (requested). +This could lead to problems, for example in this situation: + +On Disk: `text/moonscript -> fn -> mmm/dom` (a moonscript file that contains a function that returns a bit of UI) +Requested: `mmm/dom` +Known Conversions: +1. `text/moonscript` to `mmm/dom` (displays the source code with highlighting) +2. `text/moonscript -> ???` to `???` (evaluates the moonscript file) +3. `fn -> ???` to `???` (calls the function, providing access to children and other facets) + +Since conversion 1 only takes a single step, it would have been preferred by the old algorithm (although there were workarounds for this). +The new algorithm adds the concept of conversion-cost, that has to be specified for each conversion. +The conversions 2 and 3 now have a cost of `1`, while conversion 1 has a cost of `5`. +The conversions are simply added up and the path with the lowest cost is chosen. +Like in other pathfinding applications like digital games, the cost metric is also used by the algorithm to enhance the search itself, +it prioritises searching further on the path with the least current cost. + +To implement this optimization I implemented a priority queue: + + -- a priority queue with an index + -- only one element with a given key may exist at a time + -- when an element with an existing key is added, + -- the element with lower priority survives. + class Queue + new: => + @values = {} + @index = {} + + -- add a value with a given priority to the queue + -- if no key is specified, assume the element is uniq + add: (value, priority, key) => + entry = { :value, :key, :priority } + + if key + if old_entry = @index[key] + -- already have an entry for this key + -- if it is lower priority, we leave it there and do nothing + if old_entry.priority < priority + return + + -- otherwise we remove the old one and continue as normal + -- find the index of the old entry + local i + for ii, entry in ipairs @values + if entry == old_entry + i = ii + break + + -- remove it + table.remove @values, i + + -- store this entry in the index + @index[key] = entry + + -- store lowest priority last + for i, v in ipairs @values + if v.priority < priority + -- i is the first key that is lower, + -- we want to insert right before it + table.insert @values, i, entry + return + + -- couldn't find a key with a lower priority, + -- so insert at the end + table.insert @values, entry + + peek: => + entry = @values[#@values] + if entry + { :value, :priority, :key } = entry + @index[key] = nil if key + value, priority + + pop: => + entry = table.remove @values + if entry + { :value, :priority, :key } = entry + @index[key] = nil if key + value, priority + + -- iterator, yields (value, priority), low priority first + poll: => @.pop, @ + + { + :Queue + } + +This priority queue behaves mostly as expected, but I added an extra feature to make sure that only the +best conversion path to a specific type is considered for further searching: +When adding a new element to the Queue, an extra `key` can be passed. +If a key is passed, the Queue makes sure that there is only ever one element with that key in the queue. +When a second element would be introduced, the queue discards whichever element has a higher priority value. + +This way I can use the type that a conversion path leads to as the key, +and the queue will automatically discard a worse solution if a better one is found that leads to the same type result. + +To make sure the Queue implementation was solid, I also added unit tests for it: [`spec/queue_spec.moon`][spec] + +[deb21aa]: https://git.s-ol.nu/mmm/commit/deb21aa43fe8bf11eb276803973b272913b7e716/ +[spec]: https://git.s-ol.nu/mmm/blob/deb21aa43fe8bf11eb276803973b272913b7e716/spec/queue_spec.moon -- cgit v1.2.3 From ca24ef108dbb11860e719711e4e7fbd6323aee0e Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 15 Oct 2019 17:56:25 +0200 Subject: add xy-workshop --- root/articles/xy-workshop/01/text$html+frag.html | 7 +++ root/articles/xy-workshop/01b/text$markdown.md | 12 ++++ root/articles/xy-workshop/01c/text$markdown.md | 5 ++ .../xy-workshop/01c/video/URL -> youtube$video | 1 + root/articles/xy-workshop/02/text$markdown.md | 12 ++++ root/articles/xy-workshop/03/text$markdown.md | 12 ++++ root/articles/xy-workshop/04/text$markdown.md | 9 +++ root/articles/xy-workshop/05/text$markdown.md | 12 ++++ root/articles/xy-workshop/06/text$markdown.md | 6 ++ root/articles/xy-workshop/07/text$markdown.md | 6 ++ root/articles/xy-workshop/08/image/image$png.png | Bin 0 -> 285163 bytes root/articles/xy-workshop/08/text$markdown.md | 4 ++ root/articles/xy-workshop/description: text$plain | 2 + .../text$moonscript -> fn -> mmm$dom.moon | 70 +++++++++++++++++++++ 14 files changed, 158 insertions(+) create mode 100644 root/articles/xy-workshop/01/text$html+frag.html create mode 100644 root/articles/xy-workshop/01b/text$markdown.md create mode 100644 root/articles/xy-workshop/01c/text$markdown.md create mode 100644 root/articles/xy-workshop/01c/video/URL -> youtube$video create mode 100644 root/articles/xy-workshop/02/text$markdown.md create mode 100644 root/articles/xy-workshop/03/text$markdown.md create mode 100644 root/articles/xy-workshop/04/text$markdown.md create mode 100644 root/articles/xy-workshop/05/text$markdown.md create mode 100644 root/articles/xy-workshop/06/text$markdown.md create mode 100644 root/articles/xy-workshop/07/text$markdown.md create mode 100644 root/articles/xy-workshop/08/image/image$png.png create mode 100644 root/articles/xy-workshop/08/text$markdown.md create mode 100644 root/articles/xy-workshop/description: text$plain create mode 100644 root/articles/xy-workshop/text$moonscript -> fn -> mmm$dom.moon diff --git a/root/articles/xy-workshop/01/text$html+frag.html b/root/articles/xy-workshop/01/text$html+frag.html new file mode 100644 index 0000000..2441f62 --- /dev/null +++ b/root/articles/xy-workshop/01/text$html+frag.html @@ -0,0 +1,7 @@ +
+

Oscilloscope Music and Games with Pure Data

+
+
+
+

sol bekic, 2019

+
diff --git a/root/articles/xy-workshop/01b/text$markdown.md b/root/articles/xy-workshop/01b/text$markdown.md new file mode 100644 index 0000000..22c1454 --- /dev/null +++ b/root/articles/xy-workshop/01b/text$markdown.md @@ -0,0 +1,12 @@ +who am i? +========= + +my name is sol, +i like to program, build hardware and play with technology. + +- github: @s-ol +- mastodon: @s-ol\@merveilles.town +- twitter: @S0lll0s +- links to all of those, email, and more info: + https://s-ol.nu + diff --git a/root/articles/xy-workshop/01c/text$markdown.md b/root/articles/xy-workshop/01c/text$markdown.md new file mode 100644 index 0000000..ba5718c --- /dev/null +++ b/root/articles/xy-workshop/01c/text$markdown.md @@ -0,0 +1,5 @@ +what am i going to talk about? +============================== +Plonat Atek - E317 - B14 / Pavillon 6 + + diff --git a/root/articles/xy-workshop/01c/video/URL -> youtube$video b/root/articles/xy-workshop/01c/video/URL -> youtube$video new file mode 100644 index 0000000..bf07555 --- /dev/null +++ b/root/articles/xy-workshop/01c/video/URL -> youtube$video @@ -0,0 +1 @@ +https://www.youtube.com/watch?v=SIQAk9_nc-s diff --git a/root/articles/xy-workshop/02/text$markdown.md b/root/articles/xy-workshop/02/text$markdown.md new file mode 100644 index 0000000..3496b23 --- /dev/null +++ b/root/articles/xy-workshop/02/text$markdown.md @@ -0,0 +1,12 @@ +what am i going to talk about? +============================== + +
+ +- sound + scopes + - what is sound? + - what is an oscilloscope? +- pd + the audiovisual + - osc~ + output~ + - numbers boxes + sliders + - lissajous figures + sync diff --git a/root/articles/xy-workshop/03/text$markdown.md b/root/articles/xy-workshop/03/text$markdown.md new file mode 100644 index 0000000..c90491e --- /dev/null +++ b/root/articles/xy-workshop/03/text$markdown.md @@ -0,0 +1,12 @@ +what is sound? +============== +
+ +- *vibrations* in the air +- movement of your ear drum +- movement of a speaker membrane +- numbers in a file on your computer + +what do they all have in common? +- something is *changing over time* + - a wave! diff --git a/root/articles/xy-workshop/04/text$markdown.md b/root/articles/xy-workshop/04/text$markdown.md new file mode 100644 index 0000000..e07fbca --- /dev/null +++ b/root/articles/xy-workshop/04/text$markdown.md @@ -0,0 +1,9 @@ +what is sound? +============== + +waves are *something* changing over time: + +- in the air: pressure (in one spot) +- ear drum and speakers: distance from normal position +- audio cable: voltage over time +- sound file: number over time diff --git a/root/articles/xy-workshop/05/text$markdown.md b/root/articles/xy-workshop/05/text$markdown.md new file mode 100644 index 0000000..256c654 --- /dev/null +++ b/root/articles/xy-workshop/05/text$markdown.md @@ -0,0 +1,12 @@ +what is sound? +============== + +attributes of waves: + +| waves
| sounds
| | +|-------------|--------------------|----------------------------------| +| `amplitude` | `volume` | how far does the wave fluctuate? | +| `frequency` | `pitch` | how often does the wave repeat? | +| `shape` | `timbre` | (literally just the shape) | + +...let's look at + hear some examples! diff --git a/root/articles/xy-workshop/06/text$markdown.md b/root/articles/xy-workshop/06/text$markdown.md new file mode 100644 index 0000000..fa5b139 --- /dev/null +++ b/root/articles/xy-workshop/06/text$markdown.md @@ -0,0 +1,6 @@ +on computers, sound is stored as a list of `samples`: + +- `sample rate`: how many samples per second are recorded +- `sample size` or `bit depth`: how accurate is each sample + +![](https://i0.wp.com/www.mobilebeat.com/wp-content/uploads/2017/05/Screen-Shot-2017-05-05-at-3.55.46-PM.png) diff --git a/root/articles/xy-workshop/07/text$markdown.md b/root/articles/xy-workshop/07/text$markdown.md new file mode 100644 index 0000000..518b9fb --- /dev/null +++ b/root/articles/xy-workshop/07/text$markdown.md @@ -0,0 +1,6 @@ +what is an oscilloscope? +======================== + +- machine for measuring and visualizing electronic waves (voltage) + +![](https://www.electronics-notes.com/images/cathode-ray-tube-diagram-01.svg) diff --git a/root/articles/xy-workshop/08/image/image$png.png b/root/articles/xy-workshop/08/image/image$png.png new file mode 100644 index 0000000..ff82a9d Binary files /dev/null and b/root/articles/xy-workshop/08/image/image$png.png differ diff --git a/root/articles/xy-workshop/08/text$markdown.md b/root/articles/xy-workshop/08/text$markdown.md new file mode 100644 index 0000000..92ab316 --- /dev/null +++ b/root/articles/xy-workshop/08/text$markdown.md @@ -0,0 +1,4 @@ +what is an oscilloscope? +======================== + +![](/articles/xy-workshop/08/image/:image/png) diff --git a/root/articles/xy-workshop/description: text$plain b/root/articles/xy-workshop/description: text$plain new file mode 100644 index 0000000..c3fefe0 --- /dev/null +++ b/root/articles/xy-workshop/description: text$plain @@ -0,0 +1,2 @@ +workshop: oscilloscope music and games with pure data + diff --git a/root/articles/xy-workshop/text$moonscript -> fn -> mmm$dom.moon b/root/articles/xy-workshop/text$moonscript -> fn -> mmm$dom.moon new file mode 100644 index 0000000..701a14c --- /dev/null +++ b/root/articles/xy-workshop/text$moonscript -> fn -> mmm$dom.moon @@ -0,0 +1,70 @@ +import ReactiveVar, tohtml, fromhtml, text, elements from require 'mmm.component' +import article, button, div, span from elements + +=> + index = ReactiveVar 1 + slide = index\map (index) -> @children[index] + + local view + view = div { + style: + position: 'relative' + 'padding-top': '56.25%' + + div { + style: + position: 'absolute' + display: 'flex' + 'flex-direction': 'column' + top: 0 + left: 0 + right: 0 + bottom: 0 + padding: '1em' + background: '#eeeeee' + 'box-sizing': 'border-box' + + slide\map => @get 'mmm/dom' + } + } + + local left, right, viewNode + if MODE == 'CLIENT' + left = (_, e) -> + e\preventDefault! + index\transform (a) -> math.max 1, a - 1 + + right = (_, e) -> + e\preventDefault! + index\transform (a) -> math.min #@children, a + 1 + + viewNode = tohtml view + viewNode.tabIndex = 1 + viewNode\addEventListener 'keydown', (_, e) -> + switch e.key + when 'r' + e\preventDefault! + size = viewNode.offsetHeight / 15 + viewNode.style.fontSize = "#{size}px" + + when 'ArrowLeft' + left _, e + when 'ArrowRight' + right _, e + + tohtml with article! + \append div { + style: + display: 'flex' + + button '<', onclick: left + ' ' + span index\map (t) -> text t + ' ' + button '>', onclick: right + div style: flex: '1' + button 'fullscreen', onclick: (_, e) -> + e\preventDefault! + viewNode\requestFullscreen! + } + \append view -- cgit v1.2.3 From 74e6bb948fa84590b2c0b921868fa9abca6d41d2 Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 15 Oct 2019 17:57:28 +0200 Subject: better error-handling / logging --- build/server.moon | 11 +++++++---- mmm/component/init.client.moon | 3 +++ mmm/component/init.server.moon | 3 +++ mmm/init.client.moon | 2 +- mmm/init.server.moon | 2 +- mmm/mmmfs/browser.moon | 7 +++---- mmm/mmmfs/conversion.moon | 6 +++++- mmm/mmmfs/converts.moon | 3 ++- mmm/mmmfs/stores/web.moon | 1 + 9 files changed, 26 insertions(+), 12 deletions(-) diff --git a/build/server.moon b/build/server.moon index 72b5ffd..aa7bf50 100644 --- a/build/server.moon +++ b/build/server.moon @@ -73,7 +73,9 @@ class Server local store = web.WebStore({ verbose = true }) local root = fileder.Fileder(store, store:get_index(nil, -1)) - BROWSER = browser.Browser(root, path, facet, true) + local err_and_trace = function (msg) return debug.traceback(msg, 2) end + ok, BROWSER = xpcall(browser.Browser, err_and_trace, root, path, facet, true) + if not ok then error(BROWSER) end end) " else if not fileder\has_facet facet.name @@ -88,6 +90,7 @@ class Server else 501, "not implemented" + err_and_trace = (msg) -> debug.traceback msg, 2 stream: (sv, stream) => req = stream\get_headers! method = req\get ':method' @@ -102,10 +105,10 @@ class Server type = type\match '%s*(.*)' facet = Key facet, type - ok, status, body = pcall @.handle, @, method, path, facet + ok, status, body = xpcall @.handle, err_and_trace, @, method, path, facet if not ok - warn status, body - body = "Internal Server Error: #{status}" + warn "Error handling request (#{method} #{path} #{facet}):\n#{status}" + body = "Internal Server Error:\n#{status}" status = 500 res = headers.new! diff --git a/mmm/component/init.client.moon b/mmm/component/init.client.moon index c72644b..00e5e03 100644 --- a/mmm/component/init.client.moon +++ b/mmm/component/init.client.moon @@ -16,6 +16,8 @@ tohtml = (val) -> else error "not a Node: #{val}, #{type val}" +fromhtml = (node) -> :node + -- shorthand to form a text node from a string text = (str) -> document\createTextNode tostring str @@ -146,6 +148,7 @@ elements = setmetatable {}, __index: (name) => :get_or_create, -- :join, :tohtml, + :fromhtml, :text, :elements, } diff --git a/mmm/component/init.server.moon b/mmm/component/init.server.moon index 7c7fb7e..1cf2bd9 100644 --- a/mmm/component/init.server.moon +++ b/mmm/component/init.server.moon @@ -16,6 +16,8 @@ tohtml = (val) -> else error "not a Node: #{val}, #{type val}" +fromhtml = (html) -> render: -> html + -- shorthand to form a text node from strings escapes = { '&': '&' @@ -128,6 +130,7 @@ get_or_create = (elem, id, ...) -> :ReactiveElement, :get_or_create, :tohtml, + :fromhtml, :text, :elements, } diff --git a/mmm/init.client.moon b/mmm/init.client.moon index e32f25d..955b8d8 100644 --- a/mmm/init.client.moon +++ b/mmm/init.client.moon @@ -10,7 +10,7 @@ deep_tostring = (tbl, space='') -> return tbl if 'userdata' == type tbl buf = space .. tostring tbl - return buf unless 'table' == type tbl + return buf unless 'table' == (type tbl) or table.__tostring buf = buf .. ' {\n' for k,v in pairs tbl diff --git a/mmm/init.server.moon b/mmm/init.server.moon index 0fe36d5..c4d663d 100644 --- a/mmm/init.server.moon +++ b/mmm/init.server.moon @@ -4,7 +4,7 @@ MODE = 'SERVER' deep_tostring = (tbl, space='') -> buf = space .. tostring tbl - return buf unless 'table' == type tbl + return buf unless 'table' == (type tbl) or tbl.__tostring buf = buf .. ' {\n' for k,v in pairs tbl diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index f872ed9..2287c4c 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -166,7 +166,7 @@ class Browser @node = wrapper.node @render = wrapper\render - err_and_trace = (msg) -> { :msg, trace: debug.traceback! } + err_and_trace = (msg) -> debug.traceback msg, 2 default_convert = (key) => @get key.name, 'mmm/dom' -- render #browser-content @@ -177,7 +177,7 @@ class Browser if MODE == 'CLIENT' err\set pre msg warn "ERROR rendering content: #{msg}" - nil + div! active = @active\get! @@ -193,10 +193,9 @@ class Browser res elseif ok div "[no conversion path to #{prop.type}]" - elseif res and res.msg.match and res.msg\match '%[nossr%]$' + elseif res and res\match '%[nossr%]' div "[this page could not be pre-rendered on the server]" else - res = "#{res.msg}\n#{res.trace}" disp_error res get_inspector: => diff --git a/mmm/mmmfs/conversion.moon b/mmm/mmmfs/conversion.moon index 4b47bba..4700eea 100644 --- a/mmm/mmmfs/conversion.moon +++ b/mmm/mmmfs/conversion.moon @@ -77,10 +77,14 @@ print_conversions = (conversions) -> -- * value - value -- * ... - other transform parameters (fileder, key) -- returns converted value +err_and_trace = (msg) -> debug.traceback msg, 2 apply_conversions = (conversions, value, ...) -> for i=#conversions,1,-1 step = conversions[i] - value = step.convert.transform step, value, ... + ok, value = xpcall step.convert.transform, err_and_trace, step, value, ... + if not ok + f, k = ... + error "error while converting #{f} #{k} from '#{step.from}' to '#{step.to}':\n#{value}" value diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon index e4a6ddf..7a998e8 100644 --- a/mmm/mmmfs/converts.moon +++ b/mmm/mmmfs/converts.moon @@ -127,6 +127,7 @@ converts = { nolink = js_fix element\getAttribute 'nolink' inline = js_fix element\getAttribute 'inline' desc = js_fix element.innerText + desc = nil if desc == '' element\replaceWith embed path or '', facet or '', fileder, { :nolink, :inline, :desc } @@ -239,7 +240,7 @@ converts = { { inp: '(.+)', out: 'URL -> %1', - cost: 10 + cost: 5 transform: (_, fileder, key) => "#{fileder.path}/#{key.name}:#{@from}" } { diff --git a/mmm/mmmfs/stores/web.moon b/mmm/mmmfs/stores/web.moon index f3b60c7..ea17b5a 100644 --- a/mmm/mmmfs/stores/web.moon +++ b/mmm/mmmfs/stores/web.moon @@ -81,6 +81,7 @@ class WebStore extends Store coroutine.yield facet.name, facet.type load_facet: (path, name, type) => + @log "loading facet #{path} #{name}: #{type}" fetch "#{@host .. path}/#{name}: #{type}" create_facet: (path, name, type, blob) => -- cgit v1.2.3 From a5136a805d97276a081e62d3198b06bf93627cdf Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 15 Oct 2019 18:20:58 +0200 Subject: add ba_log entry 2019-10-15 --- .../mmmfs/ba_log/2019-10-15/text$markdown.md | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 root/articles/mmmfs/ba_log/2019-10-15/text$markdown.md diff --git a/root/articles/mmmfs/ba_log/2019-10-15/text$markdown.md b/root/articles/mmmfs/ba_log/2019-10-15/text$markdown.md new file mode 100644 index 0000000..d4e4121 --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-10-15/text$markdown.md @@ -0,0 +1,70 @@ +I'm giving a workshop next weekend, and I had to create the slides for that. +Since one of the aspirations of `mmmfs` is to be easily adaptable to any kind of data organization and -presentation task, +that was a good opportunity to try and implement a simple slideshow system. + +I started by creating a new fileder to hold the slideshow, [`/articles/xy-workshop`](/articles/xy-workshop/). +In the main facet, I created a MoonScript file. +Since the facet needs to access its children (the individual slides), I also used the `fn ->` type, +that injects the current fileder into the script. + +`text/moonscript -> fn -> mmm/dom` + + import ReactiveVar, tohtml, fromhtml, text, elements from require 'mmm.component' + import article, button, div, span from elements + + => + index = ReactiveVar 1 + slide = index\map (index) -> @children[index] + + local view + view = div { + style: ... -- styling ommited here + + div { + style: ... -- styling omitted here + + slide\map => @get 'mmm/dom' + } + } + + local left, right + if MODE == 'CLIENT' + left = (_, e) -> + e\preventDefault! + index\transform (a) -> math.max 1, a - 1 + + right = (_, e) -> + e\preventDefault! + index\transform (a) -> math.min #@children, a + 1 + + tohtml with article! + \append div { + button '<', onclick: left + ' ' + span index\map (t) -> text t + ' ' + button '>', onclick: right + } + \append view + +I used the `mmm.component` library that lets me create reactive UIs. +First I declare the reactive variable `index`, the current slide number. +Then I derive the `slide` reactive variable, that is defined to be the child with index `index` - +since these are `ReactiveVar`s, whenever `index` changes, `slide` will automatically load the current slide fileder. + +Then I create the main slide view, which consists mainly of two containers and some styling. +Inside, I derive another reactivevar from `slide`: whenever a new `slide` is selected, +this piece of code will request the main content in `mmm/dom` format and replace the current view content with that. + +Lastly I construct a little navigation UI, consisting of the left and right buttons. +When one of them is clicked, it modifies the `index` variable, making sure to stay in the range of existing slides. +The rest of the UI then reactively updates accordingly. + +Lastly I added keyboard controls for cycling through the slides, as well as a button to enter fullscreen mode. +You can find the extended code for that in the commit [`ca24ef1`][ca24ef1], +but it is not a lot either: with the additions the file is 70 lines long. + +With this done, it is just a matter of creating children-fileders and placing whichever content I want in them, +they behave just like any other page of the system now. + +[ca24ef1]: https://git.s-ol.nu/mmm/blob/ca24ef108dbb11860e719711e4e7fbd6323aee0e/root/articles/xy-workshop/text%24moonscript%20-%3E%20fn%20-%3E%20mmm%24dom.moon -- cgit v1.2.3 From 6ce64806736e8a043ba639eccd51896d6d09023c Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 24 Oct 2019 19:51:37 +0200 Subject: clean up JS deps for static builds --- build/server.moon | 11 ++++++++++- mmm/highlighting.moon | 11 +++++++---- mmm/mmmfs/browser.moon | 16 ++++++---------- mmm/mmmfs/layout.moon | 5 ----- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/build/server.moon b/build/server.moon index aa7bf50..35cc82e 100644 --- a/build/server.moon +++ b/build/server.moon @@ -60,7 +60,16 @@ class Server root = Fileder @store BROWSER = Browser root, path, facet.name - render BROWSER\todom!, fileder, noview: true, scripts: " + + deps = [[ + + + + + + ]] + + render BROWSER\todom!, fileder, noview: true, scripts: deps .. " - - - - - ]] buf ..= opts.scripts -- cgit v1.2.3 From 2ff6f906c498c1b742dd8437a09c97ebe29a652a Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 24 Oct 2019 19:51:49 +0200 Subject: add mermaid graph convert --- build/server.moon | 1 + mmm/mmmfs/converts.moon | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/build/server.moon b/build/server.moon index 35cc82e..4438836 100644 --- a/build/server.moon +++ b/build/server.moon @@ -63,6 +63,7 @@ class Server deps = [[ + diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon index 7a998e8..144da51 100644 --- a/mmm/mmmfs/converts.moon +++ b/mmm/mmmfs/converts.moon @@ -359,4 +359,17 @@ do .innerHTML = html } +if MODE == 'CLIENT' and window.mermaid + id_counter = 1 + table.insert converts, { + inp: 'text/mermaid-graph' + out: 'mmm/dom' + cost: 1 + transform: (source, fileder, key) => + with container = document\createElement 'div' + cb = (svg, two) => + .innerHTML = svg + id_counter += 1 + window.mermaid\render "mermaid-#{id_counter}", source, cb + } converts -- cgit v1.2.3 From 8ee96a4cdbd1e10f45186fd0119623f743d9eb33 Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 24 Oct 2019 19:52:05 +0200 Subject: add draft section of mmmfs --- .../mmmfs/mmmfs/mainstream_fs/text$mermaid-graph | 11 ++ .../mmmfs/mmmfs/schematic/text$mermaid-graph | 21 +++ root/articles/mmmfs/mmmfs/text$markdown.md | 194 +++++++++++++++++++++ 3 files changed, 226 insertions(+) create mode 100644 root/articles/mmmfs/mmmfs/mainstream_fs/text$mermaid-graph create mode 100644 root/articles/mmmfs/mmmfs/schematic/text$mermaid-graph create mode 100644 root/articles/mmmfs/mmmfs/text$markdown.md diff --git a/root/articles/mmmfs/mmmfs/mainstream_fs/text$mermaid-graph b/root/articles/mmmfs/mmmfs/mainstream_fs/text$mermaid-graph new file mode 100644 index 0000000..3227e47 --- /dev/null +++ b/root/articles/mmmfs/mmmfs/mainstream_fs/text$mermaid-graph @@ -0,0 +1,11 @@ +graph TD + Documents --> Movies --> m1{{A Movie.mp4}} + Documents --> Pictures --> vacation[Summer Vacation] + vacation --> v1{{1.jpg}} + vacation --> v2{{2.jpg}} + Pictures --> Projects + Projects --> p1{{1.jpg}} + Projects --> p2{{2.jpg}} + + classDef file fill:#f9f; + class m1,v1,v2,p1,p2 file; diff --git a/root/articles/mmmfs/mmmfs/schematic/text$mermaid-graph b/root/articles/mmmfs/mmmfs/schematic/text$mermaid-graph new file mode 100644 index 0000000..7b4f6f4 --- /dev/null +++ b/root/articles/mmmfs/mmmfs/schematic/text$mermaid-graph @@ -0,0 +1,21 @@ +graph TD + Documents --> Movies --> m1[A Movie.mp4] + m1 --> m1.f{{video/mp4}} + + Documents --> Pictures --> vacation[Summer Vacation] + vacation --> slideshow{{slideshow: script -> UI}} + vacation --> gallery{{gallery: script -> UI}} + vacation --> v1[1.jpg] + vacation --> v2[2.jpg] + v1 --> v1.f{{image/jpeg}} + v2 --> v2.f{{image/jpeg}} + + Pictures --> Projects + Projects --> p1[1.jpg] + Projects --> p2[2.jpg] + p1 --> p1.f{{image/jpeg}} + p2 --> p2.f{{image/jpeg}} + + classDef default fill:#f00,stroke:#333,stroke-width:4px; + classDef file fill:#f9f; + class slideshow,gallery,m1.f,v1.f,v2.f,p1.f,p2.f file; diff --git a/root/articles/mmmfs/mmmfs/text$markdown.md b/root/articles/mmmfs/mmmfs/text$markdown.md new file mode 100644 index 0000000..f98f0fb --- /dev/null +++ b/root/articles/mmmfs/mmmfs/text$markdown.md @@ -0,0 +1,194 @@ +`mmmfs` seeks to improve on two fronts. + +One of the main driving ideas of the mmmfs is to help data portability and use by making it simpler to inter-operate with different data formats. +This is accomplished using two major components, the *Type System and Coercion Engine* and the *Fileder Unified Data Model* for unified data storage and access. + +# The Fileder Unified Data Model +The Fileder Model is the underlying unified data storage model. +Like almost all current data storage and access models it is based fundamentally on the concept of a hierarchical tree-structure. + +schematic view of an example tree in a mainstream filesystem + +In common filesystems as pictured, data can be organized hierarchically into *folders* (or *directories*), +which serve only as containers of *files*, in which data is actually stored. +While *directories* are fully transparent to both system and user (they can be created, browser, listed and viewed by both), +*files* are, from the system perspective, mostly opaque and inert blocks of data. +Some metadata is associated with them (filesize, access permissions), +but notably the type of data is generally not actually stored in the filesystem, +but is determined loosely based on multiple heuristics based on the system and context, notably: +- Suffixes in the name are often used to indicate what kind of data a file should contain. + However there is no standardization over this, and often a suffix is used for multiple incompatible versions of a file-format. +- Many file-formats specify a specific data-pattern either at the very beginning or very end of a given file. + On unix systems the `libmagic` database and library of these so-called *magic constants* is commonly used to guess the file-type based on + these fragments of data. + However, since not all file-formats use magic constants, and since the location and value of the magic constants varies between constants, + files can often (considered to) be valid in multiple formats at the same time. + [TODO: quote: "Abusing file formats; or, Corkami, the Novella", Ange Albertini, PoC||GTFO 7] +- on UNIX systems files to be executed are checked by a variety of methods to determine which format would fit. + for script files, the "shebang" (`#!`) can be used to specify the program that should parse this file in the first line of the file. + [@TODO: src: https://stackoverflow.com/questions/23295724/how-does-linux-execute-a-file] + +It should be clear already from this short list that to mainstream operating systems, as well as the applications running on them, +the format of a file is almost completely unknown and at best educated guesses can be made. + +Users renaming extensions: + https://askubuntu.com/questions/166602/why-is-it-possible-to-convert-a-file-just-by-renaming-its-extension + https://www.quora.com/What-happens-when-you-rename-a-jpg-to-a-png-file + +In mmmfs, the example above might look like this instead: +schematic view of an example mmmfs tree + + +Superficially, this may look quite similar: there is still only two types of nodes (referred to as *fileders* and *facets*), +and again one of them, the *fileders* are used only to hierarchically organize *facets*. +Unlike *files*, *factes* don't only store a freeform *name*, there is also a dedicated *type* field associated with every *facet*, +that is explicitly designed to be understood and used by the system. + +Despite the similarities, the semantics of this system are very different: +In mainstream filesystems, each *file* stands for itself only; +i.e. in a *directory*, no relationship between *files* is assumed by default, +and files are most of the time read or used outside of the context they exist in in the filesystem. + +In mmmfs, a *facet* should only ever be considered an aspect of its *fileder*, and never as separate from it. +A *fileder* can contain multiple *facets*, but they are meant to be alternate or equivalent representations of the *fileder* itself. +Though for some uses it is required, software in general does not have to be directly aware of the *facets* existing within a *fileder*, +rather it assumes the presence of content in the representation that it requires, and simple requests it. +The *Type Coercion Engine* (see below) will then attempt to satisfy this request based on the *facets* that are in fact present. + +Semantically a *fileder*, like a *directory*, also encompasses all the other *fileders* nested within it (recursively). +Since *fileders* are the primary unit of data to be operated upon, *fileder* nesting emerges as a natural way of structuring complex data, +both for access by the system and applications, as well as the user themself. + +# The Type System & Coercion Engine +As mentioned above, *facets* store data alongside its *type*, and when applications require data from a *fileder*, +they specify the *type* (or the list of *types*) that they require the type to be in. + +In the current iteration of the type system, types are simple strings of text and loosely based on MIME-types [TOOD: quote RFC?]. +MIME types consist of a major- and minor category, and optionally a 'suffix'. +Here are some common MIME-types that are also used in mmmfs: + +- `text/html` and `text/html+frag` (mmmfs only) +- `text/javascript` +- `image/png` +- `image/jpeg` + +While these types allow some amount of specifity, they fall short of describing their content especially in cases where formats overlap: +Source code is often distributed in `.tar.gz` archive files (directory-trees that are first bundled into an `application/x-tar` archive, +and then compressed into an `application/gzip` archive). +Using either of these two types is either incorrect or insufficient information to properly treat and extract the contained data. + +To mitigate this problem, mmmfs *types* can be nested. This is denoted in mmmfs *type* strings using the `->` symbol, e.g. the mmmfs-types +`application/gzip -> application/tar -> dirtree` and `URL -> image/jpeg` describe a tar-gz-compressed directory tree and the URL linking to a JPEG-picture respectively. + +Depending on the outer type this nesting can mean different things: +for URLs the nested type is expected to be found after fetching the URL with HTTP, +compression formats are expected to contain contents of the nested types, +and executable formats are expected to output data of the nested type. + +It is a lot more important to be able to accurately describe the type of a *facet* in mmmfs than in mainstream operating systems, +because while in the latter types are mostly used only associate an application that will then prompt the user about further steps, +mmmfs uses the *type* to automatically find one or more programs to execute to convert or transform the data stored in a *facet* +into the *type* required by the application. + +This process of *type coercion* uses a database of known *converts*, that can be applied to data. +Every *convert* consists of a description of the input *types* that it can accept, the output *type* it would produce for a given input type, +as well as the code for actually converting a given piece of data. +Simple *converts* may simply consist of a fixed in and output type, +such as for example this *convert* for rendering Markdown-encoded text to a HTML hypertext fragment: + + { + inp: 'text/markdown' + out: 'text/html+frag' + transform: (value, ...) -> + -- implementation stripped for brevity + } + +Other *converts* on the other hand may accept a wide range of input types: + + { + inp: 'URL -> image/.*' + out: 'text/html+frag' + transform: (url) -> img src: url + } + +This convert uses a Lua Pattern to specify that it can accept an URL to any type of image, +and convert it to an HTML fragment. + +By using the pattern substitution syntax provided by the Lua `string.gsub` function, +converts can also make the type they return depend on the input type, as is required often when nested types are unpacked: + + { + inp: 'application/gzip -> (.*)' + out: '%1' + transform: (data) -> + -- implementation stripped for brevity + } + +This *convert* accepts an `application/gzip` *type* wrapping any other *type*, and captures that nested type in a pattern group. +It then uses the substituion syntax to specify that nested type as the output of the conversion. +For an input *type* of `application/gzip -> image/png` this *convert* would therefore generate the type `image/png`. + +To further demonstrate the flexibility using this approach, consider this last example: + + { + inp: 'text/moonscript -> (.*)' + out: 'text/lua -> %1' + transform: (code) -> moonscript.to_lua code + } + +This *convert* transpiles MoonScript source-code into Lua source-code, while keeping the nested type +(in this case the result expected when executing either script) the same. + +In addition to the attributes shown above, every *convert* is also rated with a *cost* value. +The cost value is meant to roughly estimate both the cost (in terms of computing power) of the conversion, +as well as the accuracy or immediacy of the conversion. +For example, resizing an image to a lower size should have a high cost, because the process is computationally expensive, +but also because a smaller image represents the original image to a lesser degree. +Similarily, an URL to a piece of content is a less immediate representation than the content itself, +so the cost of a *convert* that simply generates the URL to a piece of data should be high even if the process is very cheap to compute. + +Cost is defined in this way to make sure that the result of a type-coercion operation reflects the content that was present as accurately as possible. +It is also important to prevent some nonsensical results from occuring, such as displaying a link to content instead of the content itself because +the link requires less steps to create than completely converting the content does. + +*** + +Type coercion is implemented using a general pathfinding algorithm, similar to A*. +First, the set of given *types* is found by selecting all *facets* of the *fileder* that match the *name* given in the query. +The set of given *types* is marked in green in the following example graph. + +From there the algorithm recursively checks whether it can reach other types by applying all matching *converts* to the type +that is cheapest to reach, excluding any types that have already been exhaustively-searched in this way. +All types it finds, that have not yet been inserted into the set of given types are then added to the set, +so that they may be searched as well. + +The algorithm doesn't stop immediately after reaching a type from the result set, +it continues search until it either completely exhausts the result space, +or until all non-exhaustively searched paths are already higher than the maximum allowed path. +This ensures that the optimal path is found, even if a more expensive path is found more quickly initially. + +``` +graph LR +graph LR + md_lua[text/lua -> text/markdown] + md[text/markdown] + moon[text/moonscript -> fn -> mmm/dom] + lua[text/lua -> fn -> mmm/dom] + fn[fn -> mmm/dom] + dom[mmm/dom] + moon_url[URL -> text/moonscript -> fn -> mmm/dom] + lua_url[URL -> text/lua -> fn -> mmm/dom] + + md_lua -- cost: 1 --> md -- cost: 2 --> dom + moon -- cost: 5 --> moon_url + moon -- cost: 1 --> fn -- cost: 2 --> dom + moon -- cost: 2 --> lua -- cost: 5 --> lua_url + lua -- cost: 1 --> fn + moon_url -- cost: 10 --> dom + lua_url -- cost: 10 -->dom + + classDef given fill:#ada; + classDef path stroke:#ada; + linkStyle 3,1,0,4 stroke:#8d8,stroke-width:2px + class md_lua,moon given +``` -- cgit v1.2.3 From 8c4a3c747cb6d50e439c1819d6aecf299678c972 Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 24 Oct 2019 20:14:58 +0200 Subject: fix absoute paths in link_to, embed --- build/server.moon | 10 ++++------ mmm/mmmfs/browser.moon | 3 +++ mmm/mmmfs/util.moon | 8 ++++++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/build/server.moon b/build/server.moon index 4438836..33a985f 100644 --- a/build/server.moon +++ b/build/server.moon @@ -56,10 +56,8 @@ class Server convert 'table', facet.type, index, fileder, facet.name else if facet.type == 'text/html+interactive' - export BROWSER - root = Fileder @store - BROWSER = Browser root, path, facet.name + browser = Browser root, path, facet.name deps = [[ @@ -70,7 +68,7 @@ class Server ]] - render BROWSER\todom!, fileder, noview: true, scripts: deps .. " + render browser\todom!, fileder, noview: true, scripts: deps .. " " else if not fileder\has_facet facet.name diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index ffaefc0..f232f2a 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -34,8 +34,11 @@ casts = { for convert in *converts table.insert casts, convert +export BROWSER class Browser new: (@root, path, facet, rehydrate=false) => + BROWSER = @ + -- root fileder assert @root, 'root fileder is nil' diff --git a/mmm/mmmfs/util.moon b/mmm/mmmfs/util.moon index 9e0a0b0..176f4e6 100644 --- a/mmm/mmmfs/util.moon +++ b/mmm/mmmfs/util.moon @@ -14,8 +14,12 @@ tourl = (path) -> find_fileder = (fileder, origin) -> if 'string' == type fileder - assert origin, "cannot resolve path '#{fileder}' without origin!" - assert (origin\walk fileder), "couldn't resolve path '#{fileder}' from #{origin}" + if '.' == fileder\sub 1, 1 + assert origin, "cannot resolve path '#{fileder}' without origin!" + assert (origin\walk fileder), "couldn't resolve path '#{fileder}' from #{origin}" + else + assert BROWSER and BROWSER.root, "cannot resolve path '#{fileder}' without BROWSER and root set!" + assert (BROWSER.root\walk fileder), "couldn't resolve path '#{fileder}' from #{origin}" else assert fileder, "no fileder passed." -- cgit v1.2.3 From d8137ab9323d2632c0ee3ebfff2b45b253522aed Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 24 Oct 2019 20:15:10 +0200 Subject: add ba_log entry 2019-10-24 --- .../mmmfs/ba_log/2019-10-24/text$markdown.md | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 root/articles/mmmfs/ba_log/2019-10-24/text$markdown.md diff --git a/root/articles/mmmfs/ba_log/2019-10-24/text$markdown.md b/root/articles/mmmfs/ba_log/2019-10-24/text$markdown.md new file mode 100644 index 0000000..516b18d --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-10-24/text$markdown.md @@ -0,0 +1,32 @@ +While writing some of the main section of the thesis today, +I felt the need to illustrate some subject matter with a diagram depicting a folder structure. +Knowing of some similar tools that generate SVG diagrams from textual descriptions, +some quick research turned up [mermaid JS][mermaid]. + +I tried it in their online live editor first to verify that it would indeed do what I needed it to, +and then added it to the set of supported types in mmm (on the clientside only) \[[`2ff6f90`][2ff6f90]\]. +This was pretty easy in the end, all it took was adding mermaid.js to the interactive version's resources (in `build/server.moon`) +and then definig the `convert` (and thereby implicitly defining the corresponding type, `text/mermaid-graph`): + + { + inp: 'text/mermaid-graph' + out: 'mmm/dom' + cost: 1 + transform: (source) => + with container = document\createElement 'div' + cb = (svg, two) => + .innerHTML = svg + window.mermaid\render "mermaid-#{id_counter}", source, cb + } + +The code is quite short, since all it needs to do is create a container element, +then tell mermaid.js to render the textual definition. +Once mermaid.js is done, the rendered content is added in the container element. + +Here is one of the two diagrams that I implemented the feature for, +you can also follow the link through to the source and view the textual representation using the 'inspect' button. + + + +[mermaid]: https://mermaidjs.github.io/mermaid-live-editor/ +[2ff6f90]: https://git.s-ol.nu/mmm/commit/2ff6f906c498c1b742dd8437a09c97ebe29a652a/ -- cgit v1.2.3 From 258c061d24a94f62b83e19fa0535a8bca8b284c3 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 25 Oct 2019 15:41:40 +0200 Subject: fix find_fileder --- mmm/mmmfs/util.moon | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mmm/mmmfs/util.moon b/mmm/mmmfs/util.moon index 176f4e6..eb5d025 100644 --- a/mmm/mmmfs/util.moon +++ b/mmm/mmmfs/util.moon @@ -14,12 +14,12 @@ tourl = (path) -> find_fileder = (fileder, origin) -> if 'string' == type fileder - if '.' == fileder\sub 1, 1 - assert origin, "cannot resolve path '#{fileder}' without origin!" - assert (origin\walk fileder), "couldn't resolve path '#{fileder}' from #{origin}" + if '/' == fileder\sub 1, 1 + assert BROWSER and BROWSER.root, "cannot resolve absolute path '#{fileder}' without BROWSER and root set!" + assert (BROWSER.root\walk fileder), "couldn't resolve path '#{fileder}'" else - assert BROWSER and BROWSER.root, "cannot resolve path '#{fileder}' without BROWSER and root set!" - assert (BROWSER.root\walk fileder), "couldn't resolve path '#{fileder}' from #{origin}" + assert origin, "cannot resolve relative path '#{fileder}' without origin!" + assert (origin\walk fileder), "couldn't resolve path '#{fileder}' from #{origin}" else assert fileder, "no fileder passed." -- cgit v1.2.3 From 3e8b7739f32793aee4dc5ef57de19b7aff9dde8c Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 25 Oct 2019 17:10:00 +0200 Subject: fix mermaid fonts being cut --- mmm/mmmfs/converts.moon | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon index 144da51..5b1bc2c 100644 --- a/mmm/mmmfs/converts.moon +++ b/mmm/mmmfs/converts.moon @@ -360,16 +360,24 @@ do } if MODE == 'CLIENT' and window.mermaid + window.mermaid\initialize { + startOnLoad: false + fontFamily: 'monospace' + } + id_counter = 1 table.insert converts, { inp: 'text/mermaid-graph' out: 'mmm/dom' cost: 1 transform: (source, fileder, key) => + id_counter += 1 + id = "mermaid-#{id_counter}" with container = document\createElement 'div' - cb = (svg, two) => + cb = (svg) => .innerHTML = svg - id_counter += 1 - window.mermaid\render "mermaid-#{id_counter}", source, cb + window\setImmediate (_) -> + window.mermaid\render id, source, cb, container } + converts -- cgit v1.2.3 From 5e8683ac22a1a7fca8003d06587b0b402a680b2a Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 25 Oct 2019 17:10:36 +0200 Subject: rename diagrams in mmmfs/mmmfs --- .../mmmfs/ba_log/2019-10-24/text$markdown.md | 2 +- .../mmmfs/mmmfs/mainstream_fs/text$mermaid-graph | 11 -------- .../mmmfs/mmmfs/schematic/text$mermaid-graph | 21 --------------- root/articles/mmmfs/mmmfs/text$markdown.md | 30 +++------------------- .../mmmfs/mmmfs/tree_mainstream/text$mermaid-graph | 11 ++++++++ .../mmmfs/mmmfs/tree_mmmfs/text$mermaid-graph | 21 +++++++++++++++ .../mmmfs/type_coercion_graph/text$mermaid-graph | 22 ++++++++++++++++ 7 files changed, 58 insertions(+), 60 deletions(-) delete mode 100644 root/articles/mmmfs/mmmfs/mainstream_fs/text$mermaid-graph delete mode 100644 root/articles/mmmfs/mmmfs/schematic/text$mermaid-graph create mode 100644 root/articles/mmmfs/mmmfs/tree_mainstream/text$mermaid-graph create mode 100644 root/articles/mmmfs/mmmfs/tree_mmmfs/text$mermaid-graph create mode 100644 root/articles/mmmfs/mmmfs/type_coercion_graph/text$mermaid-graph diff --git a/root/articles/mmmfs/ba_log/2019-10-24/text$markdown.md b/root/articles/mmmfs/ba_log/2019-10-24/text$markdown.md index 516b18d..dbb838a 100644 --- a/root/articles/mmmfs/ba_log/2019-10-24/text$markdown.md +++ b/root/articles/mmmfs/ba_log/2019-10-24/text$markdown.md @@ -26,7 +26,7 @@ Once mermaid.js is done, the rendered content is added in the container element. Here is one of the two diagrams that I implemented the feature for, you can also follow the link through to the source and view the textual representation using the 'inspect' button. - + [mermaid]: https://mermaidjs.github.io/mermaid-live-editor/ [2ff6f90]: https://git.s-ol.nu/mmm/commit/2ff6f906c498c1b742dd8437a09c97ebe29a652a/ diff --git a/root/articles/mmmfs/mmmfs/mainstream_fs/text$mermaid-graph b/root/articles/mmmfs/mmmfs/mainstream_fs/text$mermaid-graph deleted file mode 100644 index 3227e47..0000000 --- a/root/articles/mmmfs/mmmfs/mainstream_fs/text$mermaid-graph +++ /dev/null @@ -1,11 +0,0 @@ -graph TD - Documents --> Movies --> m1{{A Movie.mp4}} - Documents --> Pictures --> vacation[Summer Vacation] - vacation --> v1{{1.jpg}} - vacation --> v2{{2.jpg}} - Pictures --> Projects - Projects --> p1{{1.jpg}} - Projects --> p2{{2.jpg}} - - classDef file fill:#f9f; - class m1,v1,v2,p1,p2 file; diff --git a/root/articles/mmmfs/mmmfs/schematic/text$mermaid-graph b/root/articles/mmmfs/mmmfs/schematic/text$mermaid-graph deleted file mode 100644 index 7b4f6f4..0000000 --- a/root/articles/mmmfs/mmmfs/schematic/text$mermaid-graph +++ /dev/null @@ -1,21 +0,0 @@ -graph TD - Documents --> Movies --> m1[A Movie.mp4] - m1 --> m1.f{{video/mp4}} - - Documents --> Pictures --> vacation[Summer Vacation] - vacation --> slideshow{{slideshow: script -> UI}} - vacation --> gallery{{gallery: script -> UI}} - vacation --> v1[1.jpg] - vacation --> v2[2.jpg] - v1 --> v1.f{{image/jpeg}} - v2 --> v2.f{{image/jpeg}} - - Pictures --> Projects - Projects --> p1[1.jpg] - Projects --> p2[2.jpg] - p1 --> p1.f{{image/jpeg}} - p2 --> p2.f{{image/jpeg}} - - classDef default fill:#f00,stroke:#333,stroke-width:4px; - classDef file fill:#f9f; - class slideshow,gallery,m1.f,v1.f,v2.f,p1.f,p2.f file; diff --git a/root/articles/mmmfs/mmmfs/text$markdown.md b/root/articles/mmmfs/mmmfs/text$markdown.md index f98f0fb..3ab6dee 100644 --- a/root/articles/mmmfs/mmmfs/text$markdown.md +++ b/root/articles/mmmfs/mmmfs/text$markdown.md @@ -7,7 +7,7 @@ This is accomplished using two major components, the *Type System and Coercion E The Fileder Model is the underlying unified data storage model. Like almost all current data storage and access models it is based fundamentally on the concept of a hierarchical tree-structure. -schematic view of an example tree in a mainstream filesystem +schematic view of an example tree in a mainstream filesystem In common filesystems as pictured, data can be organized hierarchically into *folders* (or *directories*), which serve only as containers of *files*, in which data is actually stored. @@ -36,7 +36,7 @@ Users renaming extensions: https://www.quora.com/What-happens-when-you-rename-a-jpg-to-a-png-file In mmmfs, the example above might look like this instead: -schematic view of an example mmmfs tree +schematic view of an example mmmfs tree Superficially, this may look quite similar: there is still only two types of nodes (referred to as *fileders* and *facets*), @@ -167,28 +167,4 @@ it continues search until it either completely exhausts the result space, or until all non-exhaustively searched paths are already higher than the maximum allowed path. This ensures that the optimal path is found, even if a more expensive path is found more quickly initially. -``` -graph LR -graph LR - md_lua[text/lua -> text/markdown] - md[text/markdown] - moon[text/moonscript -> fn -> mmm/dom] - lua[text/lua -> fn -> mmm/dom] - fn[fn -> mmm/dom] - dom[mmm/dom] - moon_url[URL -> text/moonscript -> fn -> mmm/dom] - lua_url[URL -> text/lua -> fn -> mmm/dom] - - md_lua -- cost: 1 --> md -- cost: 2 --> dom - moon -- cost: 5 --> moon_url - moon -- cost: 1 --> fn -- cost: 2 --> dom - moon -- cost: 2 --> lua -- cost: 5 --> lua_url - lua -- cost: 1 --> fn - moon_url -- cost: 10 --> dom - lua_url -- cost: 10 -->dom - - classDef given fill:#ada; - classDef path stroke:#ada; - linkStyle 3,1,0,4 stroke:#8d8,stroke-width:2px - class md_lua,moon given -``` +excerpt of the graph of conversion paths from two starting facets to mmm/dom diff --git a/root/articles/mmmfs/mmmfs/tree_mainstream/text$mermaid-graph b/root/articles/mmmfs/mmmfs/tree_mainstream/text$mermaid-graph new file mode 100644 index 0000000..3227e47 --- /dev/null +++ b/root/articles/mmmfs/mmmfs/tree_mainstream/text$mermaid-graph @@ -0,0 +1,11 @@ +graph TD + Documents --> Movies --> m1{{A Movie.mp4}} + Documents --> Pictures --> vacation[Summer Vacation] + vacation --> v1{{1.jpg}} + vacation --> v2{{2.jpg}} + Pictures --> Projects + Projects --> p1{{1.jpg}} + Projects --> p2{{2.jpg}} + + classDef file fill:#f9f; + class m1,v1,v2,p1,p2 file; diff --git a/root/articles/mmmfs/mmmfs/tree_mmmfs/text$mermaid-graph b/root/articles/mmmfs/mmmfs/tree_mmmfs/text$mermaid-graph new file mode 100644 index 0000000..7b4f6f4 --- /dev/null +++ b/root/articles/mmmfs/mmmfs/tree_mmmfs/text$mermaid-graph @@ -0,0 +1,21 @@ +graph TD + Documents --> Movies --> m1[A Movie.mp4] + m1 --> m1.f{{video/mp4}} + + Documents --> Pictures --> vacation[Summer Vacation] + vacation --> slideshow{{slideshow: script -> UI}} + vacation --> gallery{{gallery: script -> UI}} + vacation --> v1[1.jpg] + vacation --> v2[2.jpg] + v1 --> v1.f{{image/jpeg}} + v2 --> v2.f{{image/jpeg}} + + Pictures --> Projects + Projects --> p1[1.jpg] + Projects --> p2[2.jpg] + p1 --> p1.f{{image/jpeg}} + p2 --> p2.f{{image/jpeg}} + + classDef default fill:#f00,stroke:#333,stroke-width:4px; + classDef file fill:#f9f; + class slideshow,gallery,m1.f,v1.f,v2.f,p1.f,p2.f file; diff --git a/root/articles/mmmfs/mmmfs/type_coercion_graph/text$mermaid-graph b/root/articles/mmmfs/mmmfs/type_coercion_graph/text$mermaid-graph new file mode 100644 index 0000000..cf2cf1e --- /dev/null +++ b/root/articles/mmmfs/mmmfs/type_coercion_graph/text$mermaid-graph @@ -0,0 +1,22 @@ +graph LR + md_lua[text/lua -> text/markdown] + md[text/markdown] + moon[text/moonscript -> fn -> mmm/dom] + lua[text/lua -> fn -> mmm/dom] + fn[fn -> mmm/dom] + dom[mmm/dom] + moon_url[URL -> text/moonscript -> fn -> mmm/dom] + lua_url[URL -> text/lua -> fn -> mmm/dom] + + md_lua -- cost: 1 --> md -- cost: 2 --> dom + moon -- cost: 5 --> moon_url + moon -- cost: 1 --> fn -- cost: 2 --> dom + moon -- cost: 2 --> lua -- cost: 5 --> lua_url + lua -- cost: 1 --> fn + moon_url -- cost: 10 --> dom + lua_url -- cost: 10 -->dom + + classDef given fill:#ada; + classDef path stroke:#ada; + linkStyle 3,1,0,4 stroke:#8d8,stroke-width:2px + class md_lua,moon given -- cgit v1.2.3 From ad80c7aadac4fb42323a0a927ae80ca2de563487 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 25 Oct 2019 17:11:03 +0200 Subject: add WIP problem_statement --- .../mmmfs/problem-statement/text$markdown.md | 56 ++++++++++++++++++++++ .../mmmfs/text$moonscript -> fn -> mmm$dom.moon | 18 ------- 2 files changed, 56 insertions(+), 18 deletions(-) create mode 100644 root/articles/mmmfs/problem-statement/text$markdown.md diff --git a/root/articles/mmmfs/problem-statement/text$markdown.md b/root/articles/mmmfs/problem-statement/text$markdown.md new file mode 100644 index 0000000..d992e6e --- /dev/null +++ b/root/articles/mmmfs/problem-statement/text$markdown.md @@ -0,0 +1,56 @@ +# motivation + +The state of sof +According to some researchers in the field of Human-Computer-Interaction, the state of computing is rather dire. + +It seems that a huge majority of daily computer users have silently accepted +that real control over their most important everyday tool will be forever out of reach, +and surrendered it to the relatively small group of 'programmers' curating their experience. + +- Applications are bad +- Services are worse + + +[Cragg 2016] +D. Cragg coins the term "inert data" for the data created, and left behind, by apps and applications in the computing model that is currently prevalent: +Most data today is either intrinsically linked to one specific application, that controls and limits access to the actual information, +or even worse, stored in the cloud where users have no direct access at all and depend soley on online tools that require a stable network connection +and a modern browser, and that could be modified, removed or otherwise negatively impacted at any moment. + +Chiusano blames these issues on the metaphor of the *machine*, and likens apps and applications to appliances. +According to him, what should really be provided are *tools*: +composable pieces of software that naturally lend themselves to, or outrightly call for, +integration into the users' other systems and customization, +rather than lure into the walled-gardens of corporate ecosystems using network-effects. + +Services like this are + +not even directly accessible to end-users anymore +Data is inert ko[Cragg 2016] + +Key points: +- data ownership + data needs to be freely accessible (without depending on a 3rd party) and unconditionally accessible +- data compatibility + data needs to be usable outside the context of it's past use (in the worst case) +- functionality + user needs many, complex needs met + + +Today, computer users are losing more and more control over their data. Between web and cloud +applications holding customer data hostage for providing the services, unappealing and limited mobile file +browsing experiences and the non-interoperable, proprietary file formats holding on to their own data has +become infeasible for many users. mmmfs is an attempt at rethinking file-systems and the computer user +experience to give control back to and empower users. + +mmmfs tries to provide a filesystem that is powerful enough to let you use it as your canvas for thinking, +and working at the computer. mmmfs is made for more than just storing information. Files in mmmfs can interact +and morph to create complex behaviours. + +Let us take as an example the simple task of collecting and arranging a mixed collection of images, videos +and texts in order to brainstorm. To create an assemblage of pictures and text, many might be tempted to open an +Application like Microsoft Word or Adobe Photoshop and create a new document there. Both photoshop files and +word documents are capable of containing texts and images, but when the files are saved, direct access to the +contained data is lost. It is for example a non-trivial and unenjoyable task to edit an image file contained +in a word document in another application and have the changes apply to the document. In the same way, +text contained in a photoshop document cannot be edited in a text editor of your choice. diff --git a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon index 7bb192d..a712d2a 100644 --- a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon @@ -32,24 +32,6 @@ append h1 'mmmfs', style: { 'margin-bottom': 0 } append p "a file and operating system to live in", style: { 'margin-top': 0, 'padding-bottom': '0.2em', 'border-bottom': '1px solid black' } - append h2 "motivation" - append p "Today, computer users are losing more and more control over their data. Between web and cloud - applications holding customer data hostage for providing the services, unappealing and limited mobile file - browsing experiences and the non-interoperable, proprietary file formats holding on to their own data has - become infeasible for many users. mmmfs is an attempt at rethinking file-systems and the computer user - experience to give control back to and empower users." - - append p "mmmfs tries to provide a filesystem that is powerful enough to let you use it as your canvas for thinking, - and working at the computer. mmmfs is made for more than just storing information. Files in mmmfs can interact - and morph to create complex behaviours." - - append p "Let us take as an example the simple task of collecting and arranging a mixed collection of images, videos - and texts in order to brainstorm. To create an assemblage of pictures and text, many might be tempted to open an - Application like Microsoft Word or Adobe Photoshop and create a new document there. Both photoshop files and - word documents are capable of containing texts and images, but when the files are saved, direct access to the - contained data is lost. It is for example a non-trivial and unenjoyable task to edit an image file contained - in a word document in another application and have the changes apply to the document. In the same way, - text contained in a photoshop document cannot be edited in a text editor of your choice." append p "mmmfs tries to change all this. In mmmfs, files can contain other files and so the collage document becomes a container for the collected images and texts just as a regular directory would. This way the individual -- cgit v1.2.3 From 2bc7da49f9f3f0732cdec7abfc6e539243ebdd90 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 25 Oct 2019 19:27:08 +0200 Subject: fix bug in deep_tostring --- mmm/init.client.moon | 2 +- mmm/init.server.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mmm/init.client.moon b/mmm/init.client.moon index 955b8d8..be286d8 100644 --- a/mmm/init.client.moon +++ b/mmm/init.client.moon @@ -10,7 +10,7 @@ deep_tostring = (tbl, space='') -> return tbl if 'userdata' == type tbl buf = space .. tostring tbl - return buf unless 'table' == (type tbl) or table.__tostring + return buf unless 'table' == (type tbl) and not tbl.__tostring buf = buf .. ' {\n' for k,v in pairs tbl diff --git a/mmm/init.server.moon b/mmm/init.server.moon index c4d663d..fbce18f 100644 --- a/mmm/init.server.moon +++ b/mmm/init.server.moon @@ -4,7 +4,7 @@ MODE = 'SERVER' deep_tostring = (tbl, space='') -> buf = space .. tostring tbl - return buf unless 'table' == (type tbl) or tbl.__tostring + return buf unless 'table' == (type tbl) and not tbl.__tostring buf = buf .. ' {\n' for k,v in pairs tbl -- cgit v1.2.3 From 6a30fbd239b31e293c0833c2bbcbb8def44707f1 Mon Sep 17 00:00:00 2001 From: s-ol Date: Sat, 26 Oct 2019 13:30:58 +0200 Subject: mmmfs cleanup --- root/articles/mmmfs/abstract/text$markdown.md | 0 root/articles/mmmfs/empty/title: text$plain | 1 - root/articles/mmmfs/evaluation/text$markdown.md | 74 ++++++++ .../mmmfs/examples/empty/title: text$plain | 1 + .../examples/gallery/actual_image/image$png.png | Bin 0 -> 678429 bytes .../gallery/actual_image/preview: image$png.png | Bin 0 -> 31880 bytes .../gallery/link_to_image/URL -> image$png | 1 + .../link_to_image/preview: URL -> image$png | 1 + .../preview: text$moonscript -> fn -> mmm$dom.moon | 7 + ...ow: text$moonscript -> fn -> mmm$component.moon | 19 ++ .../gallery/text$moonscript -> fn -> mmm$dom.moon | 12 ++ .../mmmfs/examples/gallery/title: text$plain | 1 + .../articles/mmmfs/examples/image/URL -> image$png | 1 + .../preview: text$moonscript -> fn -> mmm$dom.moon | 5 + .../mmmfs/examples/image/title: text$plain | 1 + .../javascript/text$javascript -> mmm$dom.js | 15 ++ .../language_support/javascript/title: text$plain | 1 + .../language_support/lua/text$lua -> mmm$dom.lua | 9 + .../language_support/lua/title: text$plain | 1 + .../moonscript/text$moonscript -> mmm$dom.moon | 10 + .../language_support/moonscript/title: text$plain | 1 + .../language_support/preview: text$markdown | 6 + .../text$moonscript -> fn -> mmm$dom.moon | 16 ++ .../examples/language_support/title: text$plain | 1 + .../examples/markdown/preview: text$markdown.md | 6 + .../mmmfs/examples/markdown/title: text$plain | 1 + .../examples/text$moonscript -> fn -> mmm$dom.moon | 32 ++++ root/articles/mmmfs/framework/text$markdown.md | 15 ++ .../mmmfs/gallery/actual_image/image$png.png | Bin 678429 -> 0 bytes .../gallery/actual_image/preview: image$png.png | Bin 31880 -> 0 bytes .../mmmfs/gallery/link_to_image/URL -> image$png | 1 - .../link_to_image/preview: URL -> image$png | 1 - .../preview: text$moonscript -> fn -> mmm$dom.moon | 7 - ...ow: text$moonscript -> fn -> mmm$component.moon | 19 -- .../gallery/text$moonscript -> fn -> mmm$dom.moon | 12 -- root/articles/mmmfs/gallery/title: text$plain | 1 - root/articles/mmmfs/image/URL -> image$png | 1 - .../preview: text$moonscript -> fn -> mmm$dom.moon | 5 - root/articles/mmmfs/image/title: text$plain | 1 - .../javascript/text$javascript -> mmm$dom.js | 15 -- .../language_support/javascript/title: text$plain | 1 - .../language_support/lua/text$lua -> mmm$dom.lua | 9 - .../mmmfs/language_support/lua/title: text$plain | 1 - .../moonscript/text$moonscript -> mmm$dom.moon | 10 - .../language_support/moonscript/title: text$plain | 1 - .../mmmfs/language_support/preview: text$markdown | 6 - .../text$moonscript -> fn -> mmm$dom.moon | 16 -- .../mmmfs/language_support/title: text$plain | 1 - .../mmmfs/markdown/preview: text$markdown.md | 6 - root/articles/mmmfs/markdown/title: text$plain | 1 - root/articles/mmmfs/mmmfs/text$markdown.md | 24 ++- .../mmmfs/problem-statement/text$markdown.md | 60 +++++- .../mmmfs/text$moonscript -> fn -> mmm$dom.moon | 211 +-------------------- 53 files changed, 315 insertions(+), 333 deletions(-) create mode 100644 root/articles/mmmfs/abstract/text$markdown.md delete mode 100644 root/articles/mmmfs/empty/title: text$plain create mode 100644 root/articles/mmmfs/evaluation/text$markdown.md create mode 100644 root/articles/mmmfs/examples/empty/title: text$plain create mode 100644 root/articles/mmmfs/examples/gallery/actual_image/image$png.png create mode 100644 root/articles/mmmfs/examples/gallery/actual_image/preview: image$png.png create mode 100644 root/articles/mmmfs/examples/gallery/link_to_image/URL -> image$png create mode 100644 root/articles/mmmfs/examples/gallery/link_to_image/preview: URL -> image$png create mode 100644 root/articles/mmmfs/examples/gallery/preview: text$moonscript -> fn -> mmm$dom.moon create mode 100644 root/articles/mmmfs/examples/gallery/slideshow: text$moonscript -> fn -> mmm$component.moon create mode 100644 root/articles/mmmfs/examples/gallery/text$moonscript -> fn -> mmm$dom.moon create mode 100644 root/articles/mmmfs/examples/gallery/title: text$plain create mode 100644 root/articles/mmmfs/examples/image/URL -> image$png create mode 100644 root/articles/mmmfs/examples/image/preview: text$moonscript -> fn -> mmm$dom.moon create mode 100644 root/articles/mmmfs/examples/image/title: text$plain create mode 100644 root/articles/mmmfs/examples/language_support/javascript/text$javascript -> mmm$dom.js create mode 100644 root/articles/mmmfs/examples/language_support/javascript/title: text$plain create mode 100644 root/articles/mmmfs/examples/language_support/lua/text$lua -> mmm$dom.lua create mode 100644 root/articles/mmmfs/examples/language_support/lua/title: text$plain create mode 100644 root/articles/mmmfs/examples/language_support/moonscript/text$moonscript -> mmm$dom.moon create mode 100644 root/articles/mmmfs/examples/language_support/moonscript/title: text$plain create mode 100644 root/articles/mmmfs/examples/language_support/preview: text$markdown create mode 100644 root/articles/mmmfs/examples/language_support/text$moonscript -> fn -> mmm$dom.moon create mode 100644 root/articles/mmmfs/examples/language_support/title: text$plain create mode 100644 root/articles/mmmfs/examples/markdown/preview: text$markdown.md create mode 100644 root/articles/mmmfs/examples/markdown/title: text$plain create mode 100644 root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon create mode 100644 root/articles/mmmfs/framework/text$markdown.md delete mode 100644 root/articles/mmmfs/gallery/actual_image/image$png.png delete mode 100644 root/articles/mmmfs/gallery/actual_image/preview: image$png.png delete mode 100644 root/articles/mmmfs/gallery/link_to_image/URL -> image$png delete mode 100644 root/articles/mmmfs/gallery/link_to_image/preview: URL -> image$png delete mode 100644 root/articles/mmmfs/gallery/preview: text$moonscript -> fn -> mmm$dom.moon delete mode 100644 root/articles/mmmfs/gallery/slideshow: text$moonscript -> fn -> mmm$component.moon delete mode 100644 root/articles/mmmfs/gallery/text$moonscript -> fn -> mmm$dom.moon delete mode 100644 root/articles/mmmfs/gallery/title: text$plain delete mode 100644 root/articles/mmmfs/image/URL -> image$png delete mode 100644 root/articles/mmmfs/image/preview: text$moonscript -> fn -> mmm$dom.moon delete mode 100644 root/articles/mmmfs/image/title: text$plain delete mode 100644 root/articles/mmmfs/language_support/javascript/text$javascript -> mmm$dom.js delete mode 100644 root/articles/mmmfs/language_support/javascript/title: text$plain delete mode 100644 root/articles/mmmfs/language_support/lua/text$lua -> mmm$dom.lua delete mode 100644 root/articles/mmmfs/language_support/lua/title: text$plain delete mode 100644 root/articles/mmmfs/language_support/moonscript/text$moonscript -> mmm$dom.moon delete mode 100644 root/articles/mmmfs/language_support/moonscript/title: text$plain delete mode 100644 root/articles/mmmfs/language_support/preview: text$markdown delete mode 100644 root/articles/mmmfs/language_support/text$moonscript -> fn -> mmm$dom.moon delete mode 100644 root/articles/mmmfs/language_support/title: text$plain delete mode 100644 root/articles/mmmfs/markdown/preview: text$markdown.md delete mode 100644 root/articles/mmmfs/markdown/title: text$plain diff --git a/root/articles/mmmfs/abstract/text$markdown.md b/root/articles/mmmfs/abstract/text$markdown.md new file mode 100644 index 0000000..e69de29 diff --git a/root/articles/mmmfs/empty/title: text$plain b/root/articles/mmmfs/empty/title: text$plain deleted file mode 100644 index 911f98b..0000000 --- a/root/articles/mmmfs/empty/title: text$plain +++ /dev/null @@ -1 +0,0 @@ -Hey I'm an almost empty Fileder. diff --git a/root/articles/mmmfs/evaluation/text$markdown.md b/root/articles/mmmfs/evaluation/text$markdown.md new file mode 100644 index 0000000..87404cd --- /dev/null +++ b/root/articles/mmmfs/evaluation/text$markdown.md @@ -0,0 +1,74 @@ +Drawbacks & Future Work +----------------------- + +There are multiple limitations in the proposed system that have become obvious in developing and working with the system. +Some of these have been anticipated for some time and concrete research directions for solutions are apparent, +while others may be intrinsic limitations in the approach taken. + +### global set of converts +In the current system, there exists only a single, global set of *converts* that can be potentially applied +to facets anywhere in the system. +Therefore it is necessary to encode behaviour directly (as code) in facets wherever exceptional behaviour is required. +For example if a fileder conatining multiple images wants to provide custom UI for each image when viewed independently, +this code has to either be attached to every image individually (and redundantly), or added as a global convert. +To make sure this convert does not interfere with images elsewhere in the system, it would be necessary to introduce +a new type and change the images to use it, which may present yet more propblems and works against the principle of +compatibility the system has been constructed for. + +A potential direction of research in the future is to allow specifying *converts* as part of the fileder tree. +Application of *converts* could then be scoped to their fileders' subtrees, such that for any facet only the *converts* +stored in the chain of its parents upwards are considered. +This way, *converts* can be added locally if they only make sense within a given context. +Additionally it could be made possible to use this mechanism to locally override *converts* inherited from +further up in the tree, for example to specialize types based on their context in the system. + +### code outside of the system +At the moment, a large part of the mmmfs codebase is still separate from the content, and developed outside of mmmfs itself. +This is a result of the development process of mmmfs and was necessary to start the project as the filesystem itself matured, +but has become a limitation of the user experience now: +Potential users of mmmfs would generally start by becoming familiar with the operation of mmmfs from within the system, +as this is the expected (and designated) experience developed for them. +All of the code that lives outside of the mmmfs tree is therefore invisible and opaque to them, +actively limiting their understanding of, and the customizability of the system. + +This is particularily relevant for the global set of *converts*, and the layout used to render the web view, +which are expected to undergo changes as users adapt the system to their own content types and domains of interest, +as well as their visual identity, respectively. + +### superficial type system +The currently used type system based on strings and pattern matching has been largely satisfactory, +but has proven problematic for satisfying some anticipated use cases. +It should be considered to switch to a more intricate, structural type system that allows encoding more concrete meta-data +alongside the type, and to match *converts* based on a more flexible scheme of pattern matching. +For example it is envisaged to store the resolution of an image file in its type. +Many *converts* might choose to ignore this additional information, +but others could use this information to generate lower-resolution 'thumbnails' of images automatically. +Using these mechanisms for example images could be requested with a maximum-resolution constraint to save on bandwidth +when embedded in other documents. + +### type-coercion alienates +By giving the system more information about the data it is dealing with, +and then relying on the system to automatically transform between data-types, +it is easy to lose track of which format data is concretely stored in. +In much the same way that the application-centric paradigm alienates users from an understanding +and feeling of ownership of their data by overemphasizing the tools in between, +the automagical coercion of data types introduces distance between the user and an understanding of the data in the system. +It remains to be seen whether this can be mitigated with careful UX and UI design. + +### discrepancy between viewing/interacting and editing of content +Because many *converts* are not necessarily reversible, +it is very hard to implement generic ways of editing stored data in the same format it is viewed. +For example, the system trivially converts markdown-formatted text sources into viewable HTML markup, +but it is hardly possible to propagate changes to the viewable HTML back to the markdown source. +This problem worsens when the conversion path becomes more complex: +If the markdown source was fetched via HTTP from a remote URL (e.g. if the facet's type was `URL -> text/markdown`), +it is not possible to edit the content at all, since the only data owned by the system is the URL string itself, +which is not part of the viewable representation at all. +Similarily, when viewing output that is generated by code (e.g. `text/moonscript -> mmm/dom`), +the code itself is not visible to the user when interacting with the viewable representation, +and if the user wishes to change parts of the representation the system is unable to relate these changes to elements +of the code or assist the user in doing so. +As a result, the experiences of interacting with the system at large is still a very different experience than +editing content (and thereby extending the system) in it. +This is expected to represent a major hurdle for users getting started with the system, +and is a major shortcoming in enabling end-user programming as set as a goal for this project. diff --git a/root/articles/mmmfs/examples/empty/title: text$plain b/root/articles/mmmfs/examples/empty/title: text$plain new file mode 100644 index 0000000..911f98b --- /dev/null +++ b/root/articles/mmmfs/examples/empty/title: text$plain @@ -0,0 +1 @@ +Hey I'm an almost empty Fileder. diff --git a/root/articles/mmmfs/examples/gallery/actual_image/image$png.png b/root/articles/mmmfs/examples/gallery/actual_image/image$png.png new file mode 100644 index 0000000..b499413 Binary files /dev/null and b/root/articles/mmmfs/examples/gallery/actual_image/image$png.png differ diff --git a/root/articles/mmmfs/examples/gallery/actual_image/preview: image$png.png b/root/articles/mmmfs/examples/gallery/actual_image/preview: image$png.png new file mode 100644 index 0000000..f9dbfad Binary files /dev/null and b/root/articles/mmmfs/examples/gallery/actual_image/preview: image$png.png differ diff --git a/root/articles/mmmfs/examples/gallery/link_to_image/URL -> image$png b/root/articles/mmmfs/examples/gallery/link_to_image/URL -> image$png new file mode 100644 index 0000000..7cf76ff --- /dev/null +++ b/root/articles/mmmfs/examples/gallery/link_to_image/URL -> image$png @@ -0,0 +1 @@ +https://picsum.photos/600/600/?image=101 diff --git a/root/articles/mmmfs/examples/gallery/link_to_image/preview: URL -> image$png b/root/articles/mmmfs/examples/gallery/link_to_image/preview: URL -> image$png new file mode 100644 index 0000000..2b2233b --- /dev/null +++ b/root/articles/mmmfs/examples/gallery/link_to_image/preview: URL -> image$png @@ -0,0 +1 @@ +https://picsum.photos/200/200/?image=101 diff --git a/root/articles/mmmfs/examples/gallery/preview: text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/examples/gallery/preview: text$moonscript -> fn -> mmm$dom.moon new file mode 100644 index 0000000..5285629 --- /dev/null +++ b/root/articles/mmmfs/examples/gallery/preview: text$moonscript -> fn -> mmm$dom.moon @@ -0,0 +1,7 @@ +import div, img, br from require 'mmm.dom' + +=> div { + 'the first pic as a little taste:', + br!, + img src: @children[1]\get 'preview', 'URL -> image/png' +} diff --git a/root/articles/mmmfs/examples/gallery/slideshow: text$moonscript -> fn -> mmm$component.moon b/root/articles/mmmfs/examples/gallery/slideshow: text$moonscript -> fn -> mmm$component.moon new file mode 100644 index 0000000..0178ac2 --- /dev/null +++ b/root/articles/mmmfs/examples/gallery/slideshow: text$moonscript -> fn -> mmm$component.moon @@ -0,0 +1,19 @@ +import ReactiveVar, text, elements from require 'mmm.component' +import div, a, img from elements + +=> + index = ReactiveVar 1 + + prev = (i) -> math.max 1, i - 1 + next = (i) -> math.min #@children, i + 1 + + div { + div { + a 'prev', href: '#', onclick: -> index\transform prev + index\map (i) -> text " image ##{i} " + a 'next', href: '#', onclick: -> index\transform next + }, + index\map (i) -> + child = assert @children[i], "image not found!" + img src: @children[i]\gett 'URL -> image/png' + } diff --git a/root/articles/mmmfs/examples/gallery/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/examples/gallery/text$moonscript -> fn -> mmm$dom.moon new file mode 100644 index 0000000..9bdac54 --- /dev/null +++ b/root/articles/mmmfs/examples/gallery/text$moonscript -> fn -> mmm$dom.moon @@ -0,0 +1,12 @@ +import div, h1, a, img, br from require 'mmm.dom' + +=> + link = (child) -> a { + href: '#', + onclick: -> BROWSER\navigate child.path + img src: child\gett 'preview', 'URL -> image/png' + } + + content = [link child for child in *@children] + table.insert content, 1, h1 'gallery index' + div content diff --git a/root/articles/mmmfs/examples/gallery/title: text$plain b/root/articles/mmmfs/examples/gallery/title: text$plain new file mode 100644 index 0000000..ad74eec --- /dev/null +++ b/root/articles/mmmfs/examples/gallery/title: text$plain @@ -0,0 +1 @@ +A Gallery of 25 random pictures, come on in! diff --git a/root/articles/mmmfs/examples/image/URL -> image$png b/root/articles/mmmfs/examples/image/URL -> image$png new file mode 100644 index 0000000..c586722 --- /dev/null +++ b/root/articles/mmmfs/examples/image/URL -> image$png @@ -0,0 +1 @@ +https://picsum.photos/200?random diff --git a/root/articles/mmmfs/examples/image/preview: text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/examples/image/preview: text$moonscript -> fn -> mmm$dom.moon new file mode 100644 index 0000000..6c431d0 --- /dev/null +++ b/root/articles/mmmfs/examples/image/preview: text$moonscript -> fn -> mmm$dom.moon @@ -0,0 +1,5 @@ +import img from require 'mmm.dom' + +-- look for main content with 'URL to png' type +-- and wrap in an mmm/dom image tag +=> img src: @gett 'URL -> image/png' diff --git a/root/articles/mmmfs/examples/image/title: text$plain b/root/articles/mmmfs/examples/image/title: text$plain new file mode 100644 index 0000000..60a556f --- /dev/null +++ b/root/articles/mmmfs/examples/image/title: text$plain @@ -0,0 +1 @@ +Hey I'm like a link to a picture or smth diff --git a/root/articles/mmmfs/examples/language_support/javascript/text$javascript -> mmm$dom.js b/root/articles/mmmfs/examples/language_support/javascript/text$javascript -> mmm$dom.js new file mode 100644 index 0000000..de56531 --- /dev/null +++ b/root/articles/mmmfs/examples/language_support/javascript/text$javascript -> mmm$dom.js @@ -0,0 +1,15 @@ +const e = (elem, children) => { + const node = document.createElement(elem); + + if (typeof children === 'string') + node.innerText = children; + else + children.forEach(child => node.appendChild(child)); + + return node; +}; + +return e('article', [ + e('h1', 'JavaScript'), + e('p', 'JavaScript is supported natively in the browser but is not currently pre-rendered on the server.'), +]); diff --git a/root/articles/mmmfs/examples/language_support/javascript/title: text$plain b/root/articles/mmmfs/examples/language_support/javascript/title: text$plain new file mode 100644 index 0000000..581fbc7 --- /dev/null +++ b/root/articles/mmmfs/examples/language_support/javascript/title: text$plain @@ -0,0 +1 @@ +JavaScript diff --git a/root/articles/mmmfs/examples/language_support/lua/text$lua -> mmm$dom.lua b/root/articles/mmmfs/examples/language_support/lua/text$lua -> mmm$dom.lua new file mode 100644 index 0000000..62e79f1 --- /dev/null +++ b/root/articles/mmmfs/examples/language_support/lua/text$lua -> mmm$dom.lua @@ -0,0 +1,9 @@ +local d = require 'mmm.dom' + +local lua = d.a { 'Lua', href = 'https://www.lua.org/' } +local fengari = d.a { 'fengari.io', href = 'https://fengari.io/' } + +return d.article { + d.h1 'Lua', + d.p { lua, ' is fully supported using ', fengari, ' on the Client.' } +} diff --git a/root/articles/mmmfs/examples/language_support/lua/title: text$plain b/root/articles/mmmfs/examples/language_support/lua/title: text$plain new file mode 100644 index 0000000..0f9d550 --- /dev/null +++ b/root/articles/mmmfs/examples/language_support/lua/title: text$plain @@ -0,0 +1 @@ +Lua diff --git a/root/articles/mmmfs/examples/language_support/moonscript/text$moonscript -> mmm$dom.moon b/root/articles/mmmfs/examples/language_support/moonscript/text$moonscript -> mmm$dom.moon new file mode 100644 index 0000000..5cc50e6 --- /dev/null +++ b/root/articles/mmmfs/examples/language_support/moonscript/text$moonscript -> mmm$dom.moon @@ -0,0 +1,10 @@ +import a, article, h1, p from require 'mmm.dom' + +moonscript = a 'MoonScript', href: 'https://moonscript.org/' +lua = a 'Lua', href: 'https://www.lua.org/' +fengari = a 'fengari.io', href: 'https://fengari.io/' + +article { + h1 'MoonScript', + p moonscript, " is compiled to ", lua, " on the server, which is then executed on the client using ", fengari, "." +} diff --git a/root/articles/mmmfs/examples/language_support/moonscript/title: text$plain b/root/articles/mmmfs/examples/language_support/moonscript/title: text$plain new file mode 100644 index 0000000..f8871ac --- /dev/null +++ b/root/articles/mmmfs/examples/language_support/moonscript/title: text$plain @@ -0,0 +1 @@ +MoonScript diff --git a/root/articles/mmmfs/examples/language_support/preview: text$markdown b/root/articles/mmmfs/examples/language_support/preview: text$markdown new file mode 100644 index 0000000..d6c2845 --- /dev/null +++ b/root/articles/mmmfs/examples/language_support/preview: text$markdown @@ -0,0 +1,6 @@ +this Fileder contains some minimal examples showing support for various languages `mmmfs` supports currently. + +Language support is mostly limited by the fact that `mmmfs` currently targets web browsers, +on the server any scripting language that can be executed can theoretically be integrated with minimal effort. + +Using the inspector mode to view the source of the Fileders below is encouraged. diff --git a/root/articles/mmmfs/examples/language_support/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/examples/language_support/text$moonscript -> fn -> mmm$dom.moon new file mode 100644 index 0000000..4ae0679 --- /dev/null +++ b/root/articles/mmmfs/examples/language_support/text$moonscript -> fn -> mmm$dom.moon @@ -0,0 +1,16 @@ +import article, h1, p, ul, li, a from require 'mmm.dom' + +single = (a) -> a + +=> + children = for child in *@children + title = child\gett 'title: text/plain' + li a title, href: child.path, onclick: (e) => + e\preventDefault! + BROWSER\navigate child.path + + article { + h1 single @gett 'title: text/plain' + p single @gett 'preview: mmm/dom' + ul children + } diff --git a/root/articles/mmmfs/examples/language_support/title: text$plain b/root/articles/mmmfs/examples/language_support/title: text$plain new file mode 100644 index 0000000..ae06474 --- /dev/null +++ b/root/articles/mmmfs/examples/language_support/title: text$plain @@ -0,0 +1 @@ +scripting language support diff --git a/root/articles/mmmfs/examples/markdown/preview: text$markdown.md b/root/articles/mmmfs/examples/markdown/preview: text$markdown.md new file mode 100644 index 0000000..4b38ef2 --- /dev/null +++ b/root/articles/mmmfs/examples/markdown/preview: text$markdown.md @@ -0,0 +1,6 @@ +See I have like + +- a list of things +- (two things) + +and some bold **text** and `code tags` with me. diff --git a/root/articles/mmmfs/examples/markdown/title: text$plain b/root/articles/mmmfs/examples/markdown/title: text$plain new file mode 100644 index 0000000..319068d --- /dev/null +++ b/root/articles/mmmfs/examples/markdown/title: text$plain @@ -0,0 +1 @@ + I'm not even five lines of markdown but i render myself! diff --git a/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon new file mode 100644 index 0000000..ca9078c --- /dev/null +++ b/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon @@ -0,0 +1,32 @@ +-- main content +-- doesn't have a name prefix (e.g. preview: fn -> mmm/dom) +-- uses the 'fn ->' conversion to execute the lua function on @get +-- resolves to a value of type mmm/dom +=> + html = require 'mmm.dom' + import h4, div, a, span from html + + -- render a preview block + preview = (child) -> + -- get 'title' as 'text/plain' (error if no value or conversion possible) + title = child\gett 'title', 'text/plain' + + -- get 'preview' as a DOM description (nil if no value or conversion possible) + content = child\get 'preview', 'mmm/dom' + + div { + h4 title, style: { margin: 0, cursor: 'pointer' }, onclick: -> BROWSER\navigate child.path + content or span '(no renderable content)', style: { color: 'red' }, + style: { + display: 'inline-block', + width: '300px', + height: '200px', + padding: '4px', + margin: '8px', + border: '4px solid #eeeeee', + overflow: 'hidden', + }, + } + + div for child in *@children + preview child diff --git a/root/articles/mmmfs/framework/text$markdown.md b/root/articles/mmmfs/framework/text$markdown.md new file mode 100644 index 0000000..cc059ad --- /dev/null +++ b/root/articles/mmmfs/framework/text$markdown.md @@ -0,0 +1,15 @@ +Based on this, a modern data storage and processing ecosystem should enable transclusion of both content and behaviours +between contexts. +Content should be able to be transcluded and referenced to facilitate the creation of flexible data formats and interactions, +such that e.g. a slideshow slide can include content in a variety other formats (such as images and text) from anywhere else in the system. +Behaviours should be able to be transcluded and reused to facilitate the creation of ad-hoc sytems and applets based on user needs. +For example a user-created todo list should be able to take advantage of a sketching tool the user already has access to. + +The system should enable the quick creation of ad-hoc software. + +While there are drawbacks to cloud-storage of data (as outlined above), the utility of distributed systems is acknowledged, +and the system should therefore be able to include content and behaviours via the network. +This ability should be integrated deeply into the system, so that data can be treated independently of its origin and storage conditions, +with as little caveats as possible. + +The system needs to be browsable and understandable by users. diff --git a/root/articles/mmmfs/gallery/actual_image/image$png.png b/root/articles/mmmfs/gallery/actual_image/image$png.png deleted file mode 100644 index b499413..0000000 Binary files a/root/articles/mmmfs/gallery/actual_image/image$png.png and /dev/null differ diff --git a/root/articles/mmmfs/gallery/actual_image/preview: image$png.png b/root/articles/mmmfs/gallery/actual_image/preview: image$png.png deleted file mode 100644 index f9dbfad..0000000 Binary files a/root/articles/mmmfs/gallery/actual_image/preview: image$png.png and /dev/null differ diff --git a/root/articles/mmmfs/gallery/link_to_image/URL -> image$png b/root/articles/mmmfs/gallery/link_to_image/URL -> image$png deleted file mode 100644 index 7cf76ff..0000000 --- a/root/articles/mmmfs/gallery/link_to_image/URL -> image$png +++ /dev/null @@ -1 +0,0 @@ -https://picsum.photos/600/600/?image=101 diff --git a/root/articles/mmmfs/gallery/link_to_image/preview: URL -> image$png b/root/articles/mmmfs/gallery/link_to_image/preview: URL -> image$png deleted file mode 100644 index 2b2233b..0000000 --- a/root/articles/mmmfs/gallery/link_to_image/preview: URL -> image$png +++ /dev/null @@ -1 +0,0 @@ -https://picsum.photos/200/200/?image=101 diff --git a/root/articles/mmmfs/gallery/preview: text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/gallery/preview: text$moonscript -> fn -> mmm$dom.moon deleted file mode 100644 index 5285629..0000000 --- a/root/articles/mmmfs/gallery/preview: text$moonscript -> fn -> mmm$dom.moon +++ /dev/null @@ -1,7 +0,0 @@ -import div, img, br from require 'mmm.dom' - -=> div { - 'the first pic as a little taste:', - br!, - img src: @children[1]\get 'preview', 'URL -> image/png' -} diff --git a/root/articles/mmmfs/gallery/slideshow: text$moonscript -> fn -> mmm$component.moon b/root/articles/mmmfs/gallery/slideshow: text$moonscript -> fn -> mmm$component.moon deleted file mode 100644 index 0178ac2..0000000 --- a/root/articles/mmmfs/gallery/slideshow: text$moonscript -> fn -> mmm$component.moon +++ /dev/null @@ -1,19 +0,0 @@ -import ReactiveVar, text, elements from require 'mmm.component' -import div, a, img from elements - -=> - index = ReactiveVar 1 - - prev = (i) -> math.max 1, i - 1 - next = (i) -> math.min #@children, i + 1 - - div { - div { - a 'prev', href: '#', onclick: -> index\transform prev - index\map (i) -> text " image ##{i} " - a 'next', href: '#', onclick: -> index\transform next - }, - index\map (i) -> - child = assert @children[i], "image not found!" - img src: @children[i]\gett 'URL -> image/png' - } diff --git a/root/articles/mmmfs/gallery/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/gallery/text$moonscript -> fn -> mmm$dom.moon deleted file mode 100644 index 9bdac54..0000000 --- a/root/articles/mmmfs/gallery/text$moonscript -> fn -> mmm$dom.moon +++ /dev/null @@ -1,12 +0,0 @@ -import div, h1, a, img, br from require 'mmm.dom' - -=> - link = (child) -> a { - href: '#', - onclick: -> BROWSER\navigate child.path - img src: child\gett 'preview', 'URL -> image/png' - } - - content = [link child for child in *@children] - table.insert content, 1, h1 'gallery index' - div content diff --git a/root/articles/mmmfs/gallery/title: text$plain b/root/articles/mmmfs/gallery/title: text$plain deleted file mode 100644 index ad74eec..0000000 --- a/root/articles/mmmfs/gallery/title: text$plain +++ /dev/null @@ -1 +0,0 @@ -A Gallery of 25 random pictures, come on in! diff --git a/root/articles/mmmfs/image/URL -> image$png b/root/articles/mmmfs/image/URL -> image$png deleted file mode 100644 index c586722..0000000 --- a/root/articles/mmmfs/image/URL -> image$png +++ /dev/null @@ -1 +0,0 @@ -https://picsum.photos/200?random diff --git a/root/articles/mmmfs/image/preview: text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/image/preview: text$moonscript -> fn -> mmm$dom.moon deleted file mode 100644 index 6c431d0..0000000 --- a/root/articles/mmmfs/image/preview: text$moonscript -> fn -> mmm$dom.moon +++ /dev/null @@ -1,5 +0,0 @@ -import img from require 'mmm.dom' - --- look for main content with 'URL to png' type --- and wrap in an mmm/dom image tag -=> img src: @gett 'URL -> image/png' diff --git a/root/articles/mmmfs/image/title: text$plain b/root/articles/mmmfs/image/title: text$plain deleted file mode 100644 index 60a556f..0000000 --- a/root/articles/mmmfs/image/title: text$plain +++ /dev/null @@ -1 +0,0 @@ -Hey I'm like a link to a picture or smth diff --git a/root/articles/mmmfs/language_support/javascript/text$javascript -> mmm$dom.js b/root/articles/mmmfs/language_support/javascript/text$javascript -> mmm$dom.js deleted file mode 100644 index de56531..0000000 --- a/root/articles/mmmfs/language_support/javascript/text$javascript -> mmm$dom.js +++ /dev/null @@ -1,15 +0,0 @@ -const e = (elem, children) => { - const node = document.createElement(elem); - - if (typeof children === 'string') - node.innerText = children; - else - children.forEach(child => node.appendChild(child)); - - return node; -}; - -return e('article', [ - e('h1', 'JavaScript'), - e('p', 'JavaScript is supported natively in the browser but is not currently pre-rendered on the server.'), -]); diff --git a/root/articles/mmmfs/language_support/javascript/title: text$plain b/root/articles/mmmfs/language_support/javascript/title: text$plain deleted file mode 100644 index 581fbc7..0000000 --- a/root/articles/mmmfs/language_support/javascript/title: text$plain +++ /dev/null @@ -1 +0,0 @@ -JavaScript diff --git a/root/articles/mmmfs/language_support/lua/text$lua -> mmm$dom.lua b/root/articles/mmmfs/language_support/lua/text$lua -> mmm$dom.lua deleted file mode 100644 index 62e79f1..0000000 --- a/root/articles/mmmfs/language_support/lua/text$lua -> mmm$dom.lua +++ /dev/null @@ -1,9 +0,0 @@ -local d = require 'mmm.dom' - -local lua = d.a { 'Lua', href = 'https://www.lua.org/' } -local fengari = d.a { 'fengari.io', href = 'https://fengari.io/' } - -return d.article { - d.h1 'Lua', - d.p { lua, ' is fully supported using ', fengari, ' on the Client.' } -} diff --git a/root/articles/mmmfs/language_support/lua/title: text$plain b/root/articles/mmmfs/language_support/lua/title: text$plain deleted file mode 100644 index 0f9d550..0000000 --- a/root/articles/mmmfs/language_support/lua/title: text$plain +++ /dev/null @@ -1 +0,0 @@ -Lua diff --git a/root/articles/mmmfs/language_support/moonscript/text$moonscript -> mmm$dom.moon b/root/articles/mmmfs/language_support/moonscript/text$moonscript -> mmm$dom.moon deleted file mode 100644 index 5cc50e6..0000000 --- a/root/articles/mmmfs/language_support/moonscript/text$moonscript -> mmm$dom.moon +++ /dev/null @@ -1,10 +0,0 @@ -import a, article, h1, p from require 'mmm.dom' - -moonscript = a 'MoonScript', href: 'https://moonscript.org/' -lua = a 'Lua', href: 'https://www.lua.org/' -fengari = a 'fengari.io', href: 'https://fengari.io/' - -article { - h1 'MoonScript', - p moonscript, " is compiled to ", lua, " on the server, which is then executed on the client using ", fengari, "." -} diff --git a/root/articles/mmmfs/language_support/moonscript/title: text$plain b/root/articles/mmmfs/language_support/moonscript/title: text$plain deleted file mode 100644 index f8871ac..0000000 --- a/root/articles/mmmfs/language_support/moonscript/title: text$plain +++ /dev/null @@ -1 +0,0 @@ -MoonScript diff --git a/root/articles/mmmfs/language_support/preview: text$markdown b/root/articles/mmmfs/language_support/preview: text$markdown deleted file mode 100644 index d6c2845..0000000 --- a/root/articles/mmmfs/language_support/preview: text$markdown +++ /dev/null @@ -1,6 +0,0 @@ -this Fileder contains some minimal examples showing support for various languages `mmmfs` supports currently. - -Language support is mostly limited by the fact that `mmmfs` currently targets web browsers, -on the server any scripting language that can be executed can theoretically be integrated with minimal effort. - -Using the inspector mode to view the source of the Fileders below is encouraged. diff --git a/root/articles/mmmfs/language_support/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/language_support/text$moonscript -> fn -> mmm$dom.moon deleted file mode 100644 index 4ae0679..0000000 --- a/root/articles/mmmfs/language_support/text$moonscript -> fn -> mmm$dom.moon +++ /dev/null @@ -1,16 +0,0 @@ -import article, h1, p, ul, li, a from require 'mmm.dom' - -single = (a) -> a - -=> - children = for child in *@children - title = child\gett 'title: text/plain' - li a title, href: child.path, onclick: (e) => - e\preventDefault! - BROWSER\navigate child.path - - article { - h1 single @gett 'title: text/plain' - p single @gett 'preview: mmm/dom' - ul children - } diff --git a/root/articles/mmmfs/language_support/title: text$plain b/root/articles/mmmfs/language_support/title: text$plain deleted file mode 100644 index ae06474..0000000 --- a/root/articles/mmmfs/language_support/title: text$plain +++ /dev/null @@ -1 +0,0 @@ -scripting language support diff --git a/root/articles/mmmfs/markdown/preview: text$markdown.md b/root/articles/mmmfs/markdown/preview: text$markdown.md deleted file mode 100644 index 4b38ef2..0000000 --- a/root/articles/mmmfs/markdown/preview: text$markdown.md +++ /dev/null @@ -1,6 +0,0 @@ -See I have like - -- a list of things -- (two things) - -and some bold **text** and `code tags` with me. diff --git a/root/articles/mmmfs/markdown/title: text$plain b/root/articles/mmmfs/markdown/title: text$plain deleted file mode 100644 index 319068d..0000000 --- a/root/articles/mmmfs/markdown/title: text$plain +++ /dev/null @@ -1 +0,0 @@ - I'm not even five lines of markdown but i render myself! diff --git a/root/articles/mmmfs/mmmfs/text$markdown.md b/root/articles/mmmfs/mmmfs/text$markdown.md index 3ab6dee..214a720 100644 --- a/root/articles/mmmfs/mmmfs/text$markdown.md +++ b/root/articles/mmmfs/mmmfs/text$markdown.md @@ -5,25 +5,24 @@ This is accomplished using two major components, the *Type System and Coercion E # The Fileder Unified Data Model The Fileder Model is the underlying unified data storage model. -Like almost all current data storage and access models it is based fundamentally on the concept of a hierarchical tree-structure. +Like many data storage models it is based fundamentally on the concept of a hierarchical tree-structure. schematic view of an example tree in a mainstream filesystem -In common filesystems as pictured, data can be organized hierarchically into *folders* (or *directories*), +In common filesystems, as pictured, data can be organized hierarchically into *folders* (or *directories*), which serve only as containers of *files*, in which data is actually stored. While *directories* are fully transparent to both system and user (they can be created, browser, listed and viewed by both), *files* are, from the system perspective, mostly opaque and inert blocks of data. -Some metadata is associated with them (filesize, access permissions), + +Some metadata, such as file size and access permissions, is associated with each file, but notably the type of data is generally not actually stored in the filesystem, -but is determined loosely based on multiple heuristics based on the system and context, notably: +but determined loosely based on multiple heuristics depending on the system and context. +Some notable mechanism are: - Suffixes in the name are often used to indicate what kind of data a file should contain. However there is no standardization over this, and often a suffix is used for multiple incompatible versions of a file-format. - Many file-formats specify a specific data-pattern either at the very beginning or very end of a given file. On unix systems the `libmagic` database and library of these so-called *magic constants* is commonly used to guess the file-type based on these fragments of data. - However, since not all file-formats use magic constants, and since the location and value of the magic constants varies between constants, - files can often (considered to) be valid in multiple formats at the same time. - [TODO: quote: "Abusing file formats; or, Corkami, the Novella", Ange Albertini, PoC||GTFO 7] - on UNIX systems files to be executed are checked by a variety of methods to determine which format would fit. for script files, the "shebang" (`#!`) can be used to specify the program that should parse this file in the first line of the file. [@TODO: src: https://stackoverflow.com/questions/23295724/how-does-linux-execute-a-file] @@ -31,6 +30,16 @@ but is determined loosely based on multiple heuristics based on the system and c It should be clear already from this short list that to mainstream operating systems, as well as the applications running on them, the format of a file is almost completely unknown and at best educated guesses can be made. +Because these various mechanisms are applied at different times by the operating system and applications, +it is possible for files to be labelled as or considered as being in different formats at the same time by different components of the system. +This leads to confusion about the factual format of data among users (e.g. making unclear the difference between changing a file extension +and converting a file between formats [TODO: quote below]), but can also pose a serious security risk. +It is for example possible, under some circumstances, +that a file contains maliciously-crafted code and is treated as an executable by one software component, +while a security mechanism meant to detect such code determines the same file to be a legitimate image +(the file may in fact be valid in both formats). +[TODO: quote: "Abusing file formats; or, Corkami, the Novella", Ange Albertini, PoC||GTFO 7] + Users renaming extensions: https://askubuntu.com/questions/166602/why-is-it-possible-to-convert-a-file-just-by-renaming-its-extension https://www.quora.com/What-happens-when-you-rename-a-jpg-to-a-png-file @@ -38,7 +47,6 @@ Users renaming extensions: In mmmfs, the example above might look like this instead: schematic view of an example mmmfs tree - Superficially, this may look quite similar: there is still only two types of nodes (referred to as *fileders* and *facets*), and again one of them, the *fileders* are used only to hierarchically organize *facets*. Unlike *files*, *factes* don't only store a freeform *name*, there is also a dedicated *type* field associated with every *facet*, diff --git a/root/articles/mmmfs/problem-statement/text$markdown.md b/root/articles/mmmfs/problem-statement/text$markdown.md index d992e6e..78dbd76 100644 --- a/root/articles/mmmfs/problem-statement/text$markdown.md +++ b/root/articles/mmmfs/problem-statement/text$markdown.md @@ -1,6 +1,58 @@ # motivation +The application-centric computing paradigm common today is harmful to users, +because it leaves behind "intert" data as D. Cragg calls it: + +[Cragg 2016] +D. Cragg coins the term "inert data" for the data created, and left behind, by apps and applications in the computing model that is currently prevalent: +Most data today is either intrinsically linked to one specific application, that controls and limits access to the actual information, +or even worse, stored in the cloud where users have no direct access at all and depend soley on online tools that require a stable network connection +and a modern browser, and that could be modified, removed or otherwise negatively impacted at any moment. + +This issue is worsened by the fact that the a lot of software we use today is deployed through the cloud computing and SaaS paradigms, +which are far less reliable than earlier means of distributing software: +Software that runs in the cloud is subject to outages due to network problems, +pricing or availability changes etc. at the whim of the company providing it, as well as ISPs involved in the distribution. +Cloud software, as well as subscription-model software with online-verification mechanisms are additionally subject +to license changes, updates modifiying, restricting or simply removing past functionality etc. +Additionally, many cloud software solutions and ecosystems store the users' data in the cloud, +where they are subject to foreign laws and privacy concerns are intransparently handled by the companies. +Should the company, for any reason, be unable or unwanting to continue servicing a customer, +the data may be irrecoverably lost (or access prevented). + +However this lack of control over data access is not the only problem the application-centric approach induces: +Another consequence is that interoperability between applications and data formats is hindered. +Because applications are incentivised to keep customers, they make use of network effects to keep customers locked-in. +As a result applications tend to accrete features rather then modularise and delegate to other software [P Chiusano]. + +This leads to massively complex file formats, +such as for example the .docx format commonly used for storing mostly +textual data enriched with images and videos on occasion. +The docx format is in fact an archive that can contain many virtual files internally, +such as the images and videos referenced before. +However this is completely unknown to the operating system, +and so users are unable to access the contents in this way. +As a result, editing an image contained in a word document is far from a trivial task: +first the document has to be opened in a word processing application, +then the image has to be exported from it and saved in its own, temporary file. +This file can then be edited and saved back to disk. +Once updated, the image may be reimported into the .docx document. +If the word-processing application supports this, +the old image may be replaced directly, otherwise the user may have to remove the old image, +insert the new one and carefully ensure that the positioning in the document remains intact. + +In fact all of this is unnecessary, since the image had been stored in a compatible format on disk in the first place: +The system was simply unaware of this because the word document had to be archived into a single file +for ease of use by the word processor, and this single file is opaque to the system. + +Data rarely really fits the metaphora of files very well, +and even when it does it is rarely exposed to the user that way: +The 'Contacts' app on a mobile phone or laptop for example does not store each contacts's information +in a separate 'file' (as the metaphora may have initially suggested), +but rather keeps this database hidden away from the user. +Consequently, access to the information contained in the database is only enabled through the contacts applications GUI. + +-- -The state of sof According to some researchers in the field of Human-Computer-Interaction, the state of computing is rather dire. It seems that a huge majority of daily computer users have silently accepted @@ -11,12 +63,6 @@ and surrendered it to the relatively small group of 'programmers' curating their - Services are worse -[Cragg 2016] -D. Cragg coins the term "inert data" for the data created, and left behind, by apps and applications in the computing model that is currently prevalent: -Most data today is either intrinsically linked to one specific application, that controls and limits access to the actual information, -or even worse, stored in the cloud where users have no direct access at all and depend soley on online tools that require a stable network connection -and a modern browser, and that could be modified, removed or otherwise negatively impacted at any moment. - Chiusano blames these issues on the metaphor of the *machine*, and likens apps and applications to appliances. According to him, what should really be provided are *tools*: composable pieces of software that naturally lend themselves to, or outrightly call for, diff --git a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon index a712d2a..eac77c6 100644 --- a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon @@ -4,10 +4,10 @@ -- resolves to a value of type mmm/dom => html = require 'mmm.dom' - import article, h1, h2, h3, p, div, a, sup, ol, li, span, code, pre, br from html + import article, h1, h2, h3, section, p, div, a, sup, ol, li, span, code, pre, br from html import moon from (require 'mmm.highlighting').languages - article with _this = {} + article with _this = style: { margin: 'auto', 'max-width': '750px' } append = (a) -> table.insert _this, a footnote, getnotes = do @@ -32,214 +32,21 @@ append h1 'mmmfs', style: { 'margin-bottom': 0 } append p "a file and operating system to live in", style: { 'margin-top': 0, 'padding-bottom': '0.2em', 'border-bottom': '1px solid black' } - - append p "mmmfs tries to change all this. In mmmfs, files can contain other files and so the collage document - becomes a container for the collected images and texts just as a regular directory would. This way the individual - files remain accessible and can be modified whenever necessary, while the collage document can be edited to - change the order, sizes and spatial arrangement of it's content if this is wanted, for example." - - append p "The mmmfs file-type system also allows storing types of information that have become impractical to use - with current filesystems simply because noone has cared to make suitable applications for them. It is not common - practice, for example, to store direct links to online content on the disk for example. In mmmfs, a link to a - picture can be stored wherever an actual picture is expected for example, the system will take care of retrieving - the real picture as necessary." - - -- @TODO: motivation / outline problem + need - -- * applications don't let users *do* things (http://pchiusano.github.io/2013-05-22/future-of-software.html) - -- * applications are just (collections of) files - most users don't know this (anymore) - -- * users should know their system and how to move around in it - -- * filesystem trees are only *okay* for organizing information: - -- - users sooner or later choose something smarter because: - -- * filesystems work the same in every folder, even though the context can be very different - -- * appliances put their complex, structured data into opaque blocks - -- * the FS should be able to solve the structure issue - -- * the benefit is interoperability: edit the image of your report - -- * in image editor while the document editor automatically refreshes - -- * file formats dont mean much to users, they are meant for applications - let applications take care of converting them - -- * report.doc, report.pdf, report_orignal.pdf, report_old.doc, report2.doc.... - - append p do - fileder = footnote "fileder: file + folder. 'node', 'table' etc. are too general to be used all over." - - -- @TODO: mention: - -- can store anything - text, an image, a link to a website or video, - -- a program and anything else you can think of. - "in mmmfs, directories, files and applications are all kind of the same thing, or something like that. - Listen, I don't really know yet either. The idea is that there is only one type of 'thing' - - a fileder", fileder, ". A fileder can store multiple variants and metadata of its content, - such as a markdown text and a rendered HTML version of the same document. - It could also store a script that transforms the markdown version into HTML and is executed on demand, - automatically." - - append p "Fileders can also have other fileders as their children (just like directories do in a normal - filesystem). You can make a fileder view query these children and display them however you want. - A 'Pictures' fileder, for example, could contain a script within itself that renders all the picture files - you put into it as little previews and lets you click on them to view the full image." - - append p "This means the 'Pictures' fileder can also have an alternate slideshow mode, with fullscreen view and - everything (some of this is built, check out the gallery example below), or one that displays geotagged images - on a world map, if you really want that. Maybe you could build a music folder that contains links to youtube - videos, spotify tracks and just plain mp3 files, and the folder knows how to play them all.", br!, " - In this way fileders fulfil the purpose of 'Applications' too." - - -- @TODO: BUT doesn't have to be only for one type of file: - -- @TODO: rework - -- making a multi-media collage representing your thoughts and mental organization of a topic - append p "A fileder is also responsible for how it's children are sorted, filtered and interacted with. - For example you should be able to create a fileder that is essentially a 'word document' equivalent: it can - contain images, websites, links and of course text as children and let you reorder, layout and edit them - whenever you open the fileder." - - append p "Sounds cool, no? Here's some examples of things a fileder can be or embed:" - -- render a preview block - preview = (child) -> + do_section = (child) -> -- get 'title' as 'text/plain' (error if no value or conversion possible) - title = child\gett 'title', 'text/plain' + title = (child\get 'title: text/plain') or child\gett 'name: alpha' -- get 'preview' as a DOM description (nil if no value or conversion possible) - content = child\get 'preview', 'mmm/dom' + content = (child\get 'preview: mmm/dom') or child\get 'mmm/dom' - div { + section { h3 title, style: { margin: 0, cursor: 'pointer' }, onclick: -> BROWSER\navigate child.path content or span '(no renderable content)', style: { color: 'red' }, - style: { - display: 'inline-block', - width: '300px', - height: '200px', - padding: '4px', - margin: '8px', - border: '4px solid #eeeeee', - overflow: 'hidden', - }, } - append div for child in *@children - preview child - - append h2 "details" - -- @TODO s/parts: dimensions, aspects? - -- @TODO: first mention both facets & children; then go into detail - -- @TODO: main content - append do - name = html.i 'name' - type = html.i 'type' - - p "Fileders are made up of two main parts. The first is the list of ", (html.i 'facets'), ", - which are values identified by a ", name, " and ", type, ". These values are queried using strings like ", - (code 'title: text/plain'), " or ", (code 'mmm/dom'), ", which describe both the ", name, - " of a facet (", (moon '"title"'), " and ", (moon '""'), ", the unnamed/main facet) and the ", type, - " of a facet. Facet types can be something resembling a MIME-type or a more complex structure - (see ", (html.i "type chains"), " below). A fileder can have multiple facets of different types - set that share a ", name, ". In this case the overlapping facets are considered equivalent and the one - with the most appropriate ", type, " is selected, depending on the query. - The unnamed facet is considered a fileder's 'main content', i.e. what you are interested in when viewing it." - - append p "The second part of a fileder is the list of it's children, which are fileders itself. - The children are stored in an ordered list and currently identified by their ", (code 'name: alpha'), - " facet for UI and navigation purposes only (not sure if this is a good idea tbh)." - - append do - mmmdom = code ('mmm/dom'), footnote span (code 'mmm/dom'), " is a polymorphic content type; - on the server it is just an HTML string (like ", (code 'text/html'), "), - but on the client it is a JS DOM Element instance." - - p "What you are viewing right now is the main facet of the root fileder. - The facet is queried as ", mmmdom, ", a website fragment (DOM node). This website fragment - is then added to the page in the main content area, where you are most likely reading it right now." - - p "Anyway, this node is set up as a very generic sort of index thing and just lists its children-fileders' - alongside this text part you are reading.", br!, "For each child it displays the ", (code 'title: text/plain'), - " and shows the ", (code 'preview: mmm/dom'), " facet (if set)." - - append h3 "converts" - append p "So far I have always listed facets as they are being queried, but a main feature of mmmfs is - type conversion. This means that you generally ask for content in whichever format suits your application, - and rely on the type resolution mechanism to make that happen." - - append pre moon [[ --- render a preview block -preview = (title, content) -> div { - h3 title, style: { ... }, - content or span '(no renderable content)', style: { ... }, - style: { ... } -} - -append div for child in *@children --- get 'title' as 'text/plain' (error if no value or conversion possible) -title = child\gett 'title', 'text/plain' - --- get 'preview' as a DOM description (nil if no value or conversion possible) -content = child\get 'preview', 'mmm/dom' - -preview title, content - ]] - - append p "Here the code that renders these previews. You can see it ", (html.i "asks"), " for the - facets ", (code 'title: text/plain'), ' and ', (code 'preview: mmm/dom'), "), but the values don't actually have to - be ", (html.i "defined"), " as these types. - For example, the markdown child below only provides ", (code 'preview'), " as ", (code 'text/markdown'), ":" - - append pre moon [[ -Fileder { - 'title: text/plain': "I'm not even five lines of markdown but i render myself!", - 'preview: text/markdown': "See I have like - - - a list of things - - (two things) - - and some bold **text** and `code tags` with me.", -} - ]] - - append p "Then, globally, there are some conversion paths specified; such as one that maps from ", - (code 'text/markdown'), " to ", (code 'mmm/dom'), ":" - - append pre moon [[ -{ - inp: 'text/markdown', - out: 'mmm/dom', - transform: (md) -> - -- polymorphic client/serverside implementation here, - -- uses lua-discount on the server, marked.js on the client -} - ]] - - append h3 "type chains" - append p "In addition, a facet type can be encoded using multiple types in a ", (code 'type chain'), ". - For example the root node you are viewing currently is actually defined as ", (code 'fn -> mmm/dom'), ", - meaning it's value is a pre moon function returing a regular ", (code 'mmm/dom'), " value." - - append p "Both value chains and 'sideways' converts are resolved using the same mechanism, - so this page is being rendered just using ", (moon "append root\\get 'mmm/dom'"), " as well. - The convert that resolves the moon type is defined as follows:" - - append pre moon [[ -{ - inp: 'fn -> (.+)', - out: '%1', - transform: (val, fileder) -> val fileder -} - ]] - - append p "The example with the image is curious as well. In mmmfs, you might want to save a link to an image, - without ever saving the actual image on your hard drive (or wherever the data may ever be stored - it is - quite transient currently). The image Fileder below has it's main (unnamed) value tagged as ", - (code 'URL -> image/png'), " - a png image, encoded as an URL. When accessed as ", (code 'image/png'), " - the URL should be resolved, and the binary data provided in it's place (yeah right - I haven't build that yet)." - - append p "However, if a script is aware of URLs and knows a better way to handle them, then it can ask for and - use the URL directly instead. - This is what the image demo does in order to pass the URL to an ", (code 'img'), " tag's ", (code 'src'), " attribute:" - - append pre moon [[ -Fileder { - 'title: text/plain': "Hey I'm like a link to picture or smth", - 'URL -> image/png': 'https://picsum.photos/200?random', - 'preview: fn -> mmm/dom': => - import img from require 'mmm.dom' - img src: @gett 'URL -> image/png' -- look for main content with 'URL to png' type -} - ]] + for child in *@children + append child\gett 'mmm/dom' + -- do_section child append getnotes! -- cgit v1.2.3 From 987bfea00a03351323ef9d26a4b79733bb5335dd Mon Sep 17 00:00:00 2001 From: s-ol Date: Sat, 26 Oct 2019 13:31:15 +0200 Subject: fix typo --- mmm/mmmfs/converts.moon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon index 5b1bc2c..c1f7cea 100644 --- a/mmm/mmmfs/converts.moon +++ b/mmm/mmmfs/converts.moon @@ -49,7 +49,7 @@ converts = { { inp: 'mmm/component', out: 'mmm/dom', - const: 3 + cost: 3 transform: single tohtml } { -- cgit v1.2.3 From a62f63bc00cd63a98b349a2574e3e9e14c95a441 Mon Sep 17 00:00:00 2001 From: s-ol Date: Sat, 26 Oct 2019 13:42:38 +0200 Subject: implement children ordering in stores.fs --- mmm/mmmfs/stores/fs.moon | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/mmm/mmmfs/stores/fs.moon b/mmm/mmmfs/stores/fs.moon index 1300d55..8aeaf65 100644 --- a/mmm/mmmfs/stores/fs.moon +++ b/mmm/mmmfs/stores/fs.moon @@ -22,18 +22,31 @@ class FSStore extends Store -- fileders list_fileders_in: (path='') => - paths = for entry_name in lfs.dir @root .. path + entries = {} + for entry_name in lfs.dir @root .. path continue if '.' == entry_name\sub 1, 1 entry_path = @root .. "#{path}/#{entry_name}" if 'directory' ~= lfs.attributes entry_path, 'mode' continue - "#{path}/#{entry_name}" + entries[entry_name] = "#{path}/#{entry_name}" + + sorted = {} + + order_file = @root .. "#{path}/$order" + if 'file' == lfs.attributes order_file, 'mode' + for line in io.lines order_file + path = assert entries[line], "entry in $order but not on disk: #{line}" + table.insert sorted, path + sorted[line] = true + + entries = [path for entry, path in pairs entries when not sorted[entry]] + table.sort entries + for path in *entries + table.insert sorted, path - table.sort paths coroutine.wrap -> - -- @TODO: respect $order - for path in *paths + for path in *sorted coroutine.yield path create_fileder: (parent, name) => -- cgit v1.2.3 From b23af2ff33e920d3994ad4b603221c4a208c5cde Mon Sep 17 00:00:00 2001 From: s-ol Date: Sat, 26 Oct 2019 13:48:51 +0200 Subject: adjust mermaid-diagram size to content width --- mmm/mmmfs/converts.moon | 3 +++ scss/_content.scss | 3 +++ 2 files changed, 6 insertions(+) diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon index c1f7cea..f098448 100644 --- a/mmm/mmmfs/converts.moon +++ b/mmm/mmmfs/converts.moon @@ -376,6 +376,9 @@ if MODE == 'CLIENT' and window.mermaid with container = document\createElement 'div' cb = (svg) => .innerHTML = svg + .firstElementChild.style.width = '100%' + .firstElementChild.style.height = 'auto' + window\setImmediate (_) -> window.mermaid\render id, source, cb, container } diff --git a/scss/_content.scss b/scss/_content.scss index 708685f..66b9f42 100644 --- a/scss/_content.scss +++ b/scss/_content.scss @@ -8,6 +8,8 @@ .markdown > p, .markdown > p > a, .markdown > a { + max-width: 100%; + > img, > video { display: block; max-width: 100%; @@ -21,6 +23,7 @@ .embed { width: inherit; height: inherit; + max-width: inherit; .description { text-align: center; -- cgit v1.2.3 From 67ab4a90c90b60c20df59e15d334a802777197ed Mon Sep 17 00:00:00 2001 From: s-ol Date: Sat, 26 Oct 2019 13:49:05 +0200 Subject: order mmmfs article fragments --- root/articles/mmmfs/$order | 8 ++++++++ root/articles/mmmfs/references/text$markdown.md | 0 2 files changed, 8 insertions(+) create mode 100644 root/articles/mmmfs/$order create mode 100644 root/articles/mmmfs/references/text$markdown.md diff --git a/root/articles/mmmfs/$order b/root/articles/mmmfs/$order new file mode 100644 index 0000000..81fb611 --- /dev/null +++ b/root/articles/mmmfs/$order @@ -0,0 +1,8 @@ +abstract +problem-statement +framework +mmmfs +evaluation +references +ba_log +examples diff --git a/root/articles/mmmfs/references/text$markdown.md b/root/articles/mmmfs/references/text$markdown.md new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3 From 3e896d7326cd573dc39b64a3ea1d987cb42aad67 Mon Sep 17 00:00:00 2001 From: s-ol Date: Sat, 26 Oct 2019 15:56:09 +0200 Subject: print css fix --- scss/_browser.scss | 5 +++++ scss/_footer.scss | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/scss/_browser.scss b/scss/_browser.scss index 2bfc73e..b9910e8 100644 --- a/scss/_browser.scss +++ b/scss/_browser.scss @@ -47,6 +47,11 @@ position: sticky; top: 0; + @media print { + position: relative; + display: none; + } + display: flex; flex: 0 0 auto; flex-wrap: wrap; diff --git a/scss/_footer.scss b/scss/_footer.scss index 3cc3f5a..727ebda 100644 --- a/scss/_footer.scss +++ b/scss/_footer.scss @@ -4,6 +4,12 @@ footer { position: sticky; bottom: 0; + + @media print { + position: absolute; + display: none; + } + color: $gray-bright; background: $gray-dark; -- cgit v1.2.3 From 414d83dfaf534efae3bf1e87ac4aeb0af4357db4 Mon Sep 17 00:00:00 2001 From: s-ol Date: Sun, 27 Oct 2019 17:34:58 +0100 Subject: syntax highlighting in static builds --- mmm/mmmfs/layout.moon | 1 + 1 file changed, 1 insertion(+) diff --git a/mmm/mmmfs/layout.moon b/mmm/mmmfs/layout.moon index 7a1774d..05bc38b 100644 --- a/mmm/mmmfs/layout.moon +++ b/mmm/mmmfs/layout.moon @@ -144,6 +144,7 @@ render = (content, fileder, opts={}) -> " buf ..= [[ + ]] -- cgit v1.2.3 From abefbf82531021f5ca4149675932a7fe2ff37dde Mon Sep 17 00:00:00 2001 From: s-ol Date: Sun, 27 Oct 2019 17:35:35 +0100 Subject: move converts into plugins --- build/server.moon | 3 +- mmm/mmmfs/browser.moon | 4 +- mmm/mmmfs/conversion.moon | 4 +- mmm/mmmfs/converts.moon | 386 ---------------------------------------- mmm/mmmfs/init.moon | 11 +- mmm/mmmfs/plugins/code.moon | 16 ++ mmm/mmmfs/plugins/init.moon | 292 ++++++++++++++++++++++++++++++ mmm/mmmfs/plugins/markdown.moon | 33 ++++ mmm/mmmfs/plugins/mermaid.moon | 29 +++ mmm/mmmfs/plugins/twitter.moon | 22 +++ mmm/mmmfs/plugins/youtube.moon | 27 +++ 11 files changed, 427 insertions(+), 400 deletions(-) delete mode 100644 mmm/mmmfs/converts.moon create mode 100644 mmm/mmmfs/plugins/code.moon create mode 100644 mmm/mmmfs/plugins/init.moon create mode 100644 mmm/mmmfs/plugins/markdown.moon create mode 100644 mmm/mmmfs/plugins/mermaid.moon create mode 100644 mmm/mmmfs/plugins/twitter.moon create mode 100644 mmm/mmmfs/plugins/youtube.moon diff --git a/build/server.moon b/build/server.moon index 33a985f..33853c9 100644 --- a/build/server.moon +++ b/build/server.moon @@ -8,6 +8,7 @@ add '?/init' add '?/init.server' require 'mmm' +require 'mmm.mmmfs' import dir_base, Key, Fileder from require 'mmm.mmmfs.fileder' import convert from require 'mmm.mmmfs.conversion' @@ -65,7 +66,7 @@ class Server - + ]] render browser\todom!, fileder, noview: true, scripts: deps .. " diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index f232f2a..35925d3 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -1,10 +1,10 @@ require = relative ..., 1 import Key from require '.fileder' +import converts from require '.plugins' import get_conversions, apply_conversions from require '.conversion' import ReactiveVar, get_or_create, text, elements, tohtml from require 'mmm.component' import pre, div, nav, span, button, a, code, select, option from elements import languages from require 'mmm.highlighting' -converts = require '.converts' keep = (var) -> last = var\get! @@ -12,8 +12,6 @@ keep = (var) -> last = val or last last -code_cast = (lang) -> - casts = { { inp: 'text/.*', diff --git a/mmm/mmmfs/conversion.moon b/mmm/mmmfs/conversion.moon index 4700eea..c0505a8 100644 --- a/mmm/mmmfs/conversion.moon +++ b/mmm/mmmfs/conversion.moon @@ -1,5 +1,4 @@ require = relative ..., 1 -base_converts = require '.converts' import Queue from require '.queue' count = (base, pattern='->') -> select 2, base\gsub pattern, '' @@ -13,8 +12,9 @@ local print_conversions -- * want - stop type pattern -- * limit - limit conversion amount -- returns a list of conversion steps -get_conversions = (want, have, converts=base_converts, limit=5) -> +get_conversions = (want, have, converts=PLUGINS and PLUGINS.converts, limit=5) -> assert have, 'need starting type(s)' + assert converts, 'need to pass list of converts' if 'string' == type have have = { have } diff --git a/mmm/mmmfs/converts.moon b/mmm/mmmfs/converts.moon deleted file mode 100644 index f098448..0000000 --- a/mmm/mmmfs/converts.moon +++ /dev/null @@ -1,386 +0,0 @@ -require = relative ..., 1 -import div, pre, code, img, video, blockquote, a, span, source, iframe from require 'mmm.dom' -import find_fileder, link_to, embed from (require 'mmm.mmmfs.util') require 'mmm.dom' -import render from require '.layout' -import tohtml from require 'mmm.component' -import languages from require 'mmm.highlighting' - -keep = (var) -> - last = var\get! - var\map (val) -> - last = val or last - last - --- fix JS null values -js_fix = if MODE == 'CLIENT' - (arg) -> - return if arg == js.null - arg - --- limit function to one argument -single = (func) -> (val) => func val - --- load a chunk using a specific 'load'er -loadwith = (_load) -> (val, fileder, key) => - func = assert _load val, "#{fileder}##{key}" - func! - --- highlight code -code_hl = (lang) -> - { - inp: "text/#{lang}", - out: 'mmm/dom', - cost: 5 - transform: (val) => pre languages[lang] val - } - --- list of converts --- converts each have --- * inp - input type. can capture subtypes using `(.+)` --- * out - output type. can substitute subtypes from inp with %1, %2 etc. --- * transform - function (val: inp, fileder) -> val: out -converts = { - { - inp: 'fn -> (.+)', - out: '%1', - cost: 1 - transform: (val, fileder) => val fileder - } - { - inp: 'mmm/component', - out: 'mmm/dom', - cost: 3 - transform: single tohtml - } - { - inp: 'mmm/dom', - out: 'text/html+frag', - cost: 3 - transform: (node) => if MODE == 'SERVER' then node else node.outerHTML - } - { - -- inp: 'text/html%+frag', - -- @TODO: this doesn't feel right... maybe mmm/dom has to go? - inp: 'mmm/dom', - out: 'text/html', - cost: 3 - transform: (html, fileder) => render html, fileder - } - { - inp: 'text/html%+frag', - out: 'mmm/dom', - cost: 1 - transform: if MODE == 'SERVER' - (html, fileder) => - html = html\gsub '(.-)', (attrs, text) -> - text = nil if #text == 0 - path = '' - while attrs and attrs != '' - key, val, _attrs = attrs\match '^(%w+)="([^"]-)"%s*(.*)' - if not key - key, _attrs = attrs\match '^(%w+)%s*(.*)$' - val = true - - attrs = _attrs - - switch key - when 'path' then path = val - else warn "unkown attribute '#{key}=\"#{val}\"' in " - - link_to path, text, fileder - - html = html\gsub '(.-)', (attrs, desc) -> - path, facet = '', '' - opts = {} - if #desc != 0 - opts.desc = desc - - while attrs and attrs != '' - key, val, _attrs = attrs\match '^(%w+)="([^"]-)"%s*(.*)' - if not key - key, _attrs = attrs\match '^(%w+)%s*(.*)$' - val = true - - attrs = _attrs - - switch key - when 'path' then path = val - when 'facet' then facet = val - when 'nolink' then opts.nolink = true - when 'inline' then opts.inline = true - else warn "unkown attribute '#{key}=\"#{val}\"' in " - - embed path, facet, fileder, opts - - html - else - (html, fileder) => - parent = with document\createElement 'div' - .innerHTML = html - - -- copy to iterate safely, HTMLCollections update when nodes are GC'ed - embeds = \getElementsByTagName 'mmm-embed' - embeds = [embeds[i] for i=0, embeds.length - 1] - for element in *embeds - path = js_fix element\getAttribute 'path' - facet = js_fix element\getAttribute 'facet' - nolink = js_fix element\getAttribute 'nolink' - inline = js_fix element\getAttribute 'inline' - desc = js_fix element.innerText - desc = nil if desc == '' - - element\replaceWith embed path or '', facet or '', fileder, { :nolink, :inline, :desc } - - embeds = \getElementsByTagName 'mmm-link' - embeds = [embeds[i] for i=0, embeds.length - 1] - for element in *embeds - text = js_fix element.innerText - path = js_fix element\getAttribute 'path' - - element\replaceWith link_to path or '', text, fileder - - assert 1 == parent.childElementCount, "text/html with more than one child!" - parent.firstElementChild - } - { - inp: 'text/lua -> (.+)', - out: '%1', - cost: 0.5 - transform: loadwith load or loadstring - } - { - inp: 'mmm/tpl -> (.+)', - out: '%1', - cost: 1 - transform: (source, fileder) => - source\gsub '{{(.-)}}', (expr) -> - path, facet = expr\match '^([%w%-_%./]*)%+(.*)' - assert path, "couldn't match TPL expression '#{expr}'" - - (find_fileder path, fileder)\gett facet - } - { - inp: 'time/iso8601-date', - out: 'time/unix', - cost: 0.5 - transform: (val) => - year, _, month, day = val\match '^%s*(%d%d%d%d)(%-?)([01]%d)%2([0-3]%d)%s*$' - assert year, "failed to parse ISO 8601 date: '#{val}'" - os.time :year, :month, :day - } - { - inp: 'URL -> twitter/tweet', - out: 'mmm/dom', - cost: 1 - transform: (href) => - id = assert (href\match 'twitter.com/[^/]-/status/(%d*)'), "couldn't parse twitter/tweet URL: '#{href}'" - if MODE == 'CLIENT' - with parent = div! - window.twttr.widgets\createTweet id, parent - else - div blockquote { - class: 'twitter-tweet' - 'data-lang': 'en' - a '(linked tweet)', :href - } - } - { - inp: 'URL -> youtube/video', - out: 'mmm/dom', - cost: 1 - transform: (link) => - id = link\match 'youtu%.be/([^/]+)' - id or= link\match 'youtube.com/watch.*[?&]v=([^&]+)' - id or= link\match 'youtube.com/[ev]/([^/]+)' - id or= link\match 'youtube.com/embed/([^/]+)' - - assert id, "couldn't parse youtube URL: '#{link}'" - - iframe { - width: 560 - height: 315 - frameborder: 0 - allowfullscreen: true - frameBorder: 0 - src: "//www.youtube.com/embed/#{id}" - } - } - { - inp: 'URL -> image/.+', - out: 'mmm/dom', - cost: 1 - transform: (src, fileder) => img :src - } - { - inp: 'URL -> video/.+', - out: 'mmm/dom', - cost: 1 - transform: (src) => - -- @TODO: add parsed MIME type - video (source :src), controls: true, loop: true - } - { - inp: 'text/plain', - out: 'mmm/dom', - cost: 2 - transform: (val) => span val - } - { - inp: 'alpha', - out: 'mmm/dom', - cost: 2 - transform: single code - } - -- this one needs a higher cost - -- { - -- inp: 'URL -> .+', - -- out: 'mmm/dom', - -- transform: single code - -- } - { - inp: '(.+)', - out: 'URL -> %1', - cost: 5 - transform: (_, fileder, key) => "#{fileder.path}/#{key.name}:#{@from}" - } - { - inp: 'table', - out: 'text/json', - cost: 2 - transform: do - tojson = (obj) -> - switch type obj - when 'string' - string.format '%q', obj - when 'table' - if obj[1] or not next obj - "[#{table.concat [tojson c for c in *obj], ','}]" - else - "{#{table.concat ["#{tojson k}: #{tojson v}" for k,v in pairs obj], ', '}}" - when 'number' - tostring obj - when 'boolean' - tostring obj - when 'nil' - 'null' - else - error "unknown type '#{type obj}'" - - (val) => tojson val - } - { - inp: 'table', - out: 'mmm/dom', - cost: 5 - transform: do - deep_tostring = (tbl, space='') -> - buf = space .. tostring tbl - - return buf unless 'table' == type tbl - - buf = buf .. ' {\n' - for k,v in pairs tbl - buf = buf .. "#{space} [#{k}]: #{deep_tostring v, space .. ' '}\n" - buf = buf .. "#{space}}" - buf - - (tbl) => pre code deep_tostring tbl - } - code_hl 'javascript' - code_hl 'moonscript' - code_hl 'lua' - code_hl 'markdown' - code_hl 'css' -} - -if MODE == 'SERVER' - ok, moon = pcall require, 'moonscript.base' - if ok - _load = moon.load or moon.loadstring - table.insert converts, { - inp: 'text/moonscript -> (.+)', - out: '%1', - cost: 1 - transform: loadwith moon.load or moon.loadstring - } - - table.insert converts, { - inp: 'text/moonscript -> (.+)', - out: 'text/lua -> %1', - cost: 2 - transform: single moon.to_lua - } -else - table.insert converts, { - inp: 'text/javascript -> (.+)', - out: '%1', - cost: 1 - transform: (source) => - f = js.new window.Function, source - f! - } - -do - local markdown - if MODE == 'SERVER' - success, discount = pcall require, 'discount' - if not success - warn "NO MARKDOWN SUPPORT!", discount - - markdown = success and (md) -> - res = assert discount.compile md, 'githubtags' - res.body - else - markdown = window and window.marked and window\marked - - if markdown - table.insert converts, { - inp: 'text/markdown', - out: 'text/html+frag', - cost: 1 - transform: (md) => "
#{markdown md}
" - } - - table.insert converts, { - inp: 'text/markdown%+span', - out: 'mmm/dom', - cost: 1 - transform: if MODE == 'SERVER' - (source) => - html = markdown source - html = html\gsub '^$', '/span>' - else - (source) => - html = markdown source - html = html\gsub '^%s*

%s*', '' - html = html\gsub '%s*

%s*$', '' - with document\createElement 'span' - .innerHTML = html - } - -if MODE == 'CLIENT' and window.mermaid - window.mermaid\initialize { - startOnLoad: false - fontFamily: 'monospace' - } - - id_counter = 1 - table.insert converts, { - inp: 'text/mermaid-graph' - out: 'mmm/dom' - cost: 1 - transform: (source, fileder, key) => - id_counter += 1 - id = "mermaid-#{id_counter}" - with container = document\createElement 'div' - cb = (svg) => - .innerHTML = svg - .firstElementChild.style.width = '100%' - .firstElementChild.style.height = 'auto' - - window\setImmediate (_) -> - window.mermaid\render id, source, cb, container - } - -converts diff --git a/mmm/mmmfs/init.moon b/mmm/mmmfs/init.moon index 8aba86a..fc89d7f 100644 --- a/mmm/mmmfs/init.moon +++ b/mmm/mmmfs/init.moon @@ -1,9 +1,4 @@ -require = relative ... -import Key, Fileder from require '.fileder' -import Browser from require '.browser' +require = relative ..., 0 -{ - :Key - :Fileder - :Browser -} +export ^ +PLUGINS = require '.plugins' diff --git a/mmm/mmmfs/plugins/code.moon b/mmm/mmmfs/plugins/code.moon new file mode 100644 index 0000000..ec22f71 --- /dev/null +++ b/mmm/mmmfs/plugins/code.moon @@ -0,0 +1,16 @@ +import pre from require 'mmm.dom' +import languages from require 'mmm.highlighting' + +-- syntax-highlighted code +{ + converts: { + { + inp: 'text/([^ ]*).*' + out: 'mmm/dom' + cost: 5 + transform: (val) => + lang = @from\match @convert.inp + pre languages[lang] val + } + } +} diff --git a/mmm/mmmfs/plugins/init.moon b/mmm/mmmfs/plugins/init.moon new file mode 100644 index 0000000..af4a2aa --- /dev/null +++ b/mmm/mmmfs/plugins/init.moon @@ -0,0 +1,292 @@ +require = relative ..., 1 +import div, pre, code, img, video, span, source from require 'mmm.dom' +import find_fileder, link_to, embed from (require 'mmm.mmmfs.util') require 'mmm.dom' +import render from require '.layout' +import tohtml from require 'mmm.component' + +keep = (var) -> + last = var\get! + var\map (val) -> + last = val or last + last + +-- fix JS null values +js_fix = if MODE == 'CLIENT' + (arg) -> + return if arg == js.null + arg + +-- limit function to one argument +single = (func) -> (val) => func val + +-- load a chunk using a specific 'load'er +loadwith = (_load) -> (val, fileder, key) => + func = assert _load val, "#{fileder}##{key}" + func! + +-- list of converts +-- converts each have +-- * inp - input type. can capture subtypes using `(.+)` +-- * out - output type. can substitute subtypes from inp with %1, %2 etc. +-- * cost - conversion cost +-- * transform - function (val: inp, fileder) => val: out +-- @convert, @from, @to contain the convert and the concrete types +converts = { + { + inp: 'fn -> (.+)', + out: '%1', + cost: 1 + transform: (val, fileder) => val fileder + } + { + inp: 'mmm/component', + out: 'mmm/dom', + cost: 3 + transform: single tohtml + } + { + inp: 'mmm/dom', + out: 'text/html+frag', + cost: 3 + transform: (node) => if MODE == 'SERVER' then node else node.outerHTML + } + { + -- inp: 'text/html%+frag', + -- @TODO: this doesn't feel right... maybe mmm/dom has to go? + inp: 'mmm/dom', + out: 'text/html', + cost: 3 + transform: (html, fileder) => render html, fileder + } + { + inp: 'text/html%+frag', + out: 'mmm/dom', + cost: 1 + transform: if MODE == 'SERVER' + (html, fileder) => + html = html\gsub '(.-)', (attrs, text) -> + text = nil if #text == 0 + path = '' + while attrs and attrs != '' + key, val, _attrs = attrs\match '^(%w+)="([^"]-)"%s*(.*)' + if not key + key, _attrs = attrs\match '^(%w+)%s*(.*)$' + val = true + + attrs = _attrs + + switch key + when 'path' then path = val + else warn "unkown attribute '#{key}=\"#{val}\"' in " + + link_to path, text, fileder + + html = html\gsub '(.-)', (attrs, desc) -> + path, facet = '', '' + opts = {} + if #desc != 0 + opts.desc = desc + + while attrs and attrs != '' + key, val, _attrs = attrs\match '^(%w+)="([^"]-)"%s*(.*)' + if not key + key, _attrs = attrs\match '^(%w+)%s*(.*)$' + val = true + + attrs = _attrs + + switch key + when 'path' then path = val + when 'facet' then facet = val + when 'nolink' then opts.nolink = true + when 'inline' then opts.inline = true + else warn "unkown attribute '#{key}=\"#{val}\"' in " + + embed path, facet, fileder, opts + + html + else + (html, fileder) => + parent = with document\createElement 'div' + .innerHTML = html + + -- copy to iterate safely, HTMLCollections update when nodes are GC'ed + embeds = \getElementsByTagName 'mmm-embed' + embeds = [embeds[i] for i=0, embeds.length - 1] + for element in *embeds + path = js_fix element\getAttribute 'path' + facet = js_fix element\getAttribute 'facet' + nolink = js_fix element\getAttribute 'nolink' + inline = js_fix element\getAttribute 'inline' + desc = js_fix element.innerText + desc = nil if desc == '' + + element\replaceWith embed path or '', facet or '', fileder, { :nolink, :inline, :desc } + + embeds = \getElementsByTagName 'mmm-link' + embeds = [embeds[i] for i=0, embeds.length - 1] + for element in *embeds + text = js_fix element.innerText + path = js_fix element\getAttribute 'path' + + element\replaceWith link_to path or '', text, fileder + + assert 1 == parent.childElementCount, "text/html with more than one child!" + parent.firstElementChild + } + { + inp: 'text/lua -> (.+)', + out: '%1', + cost: 0.5 + transform: loadwith load or loadstring + } + { + inp: 'mmm/tpl -> (.+)', + out: '%1', + cost: 1 + transform: (source, fileder) => + source\gsub '{{(.-)}}', (expr) -> + path, facet = expr\match '^([%w%-_%./]*)%+(.*)' + assert path, "couldn't match TPL expression '#{expr}'" + + (find_fileder path, fileder)\gett facet + } + { + inp: 'time/iso8601-date', + out: 'time/unix', + cost: 0.5 + transform: (val) => + year, _, month, day = val\match '^%s*(%d%d%d%d)(%-?)([01]%d)%2([0-3]%d)%s*$' + assert year, "failed to parse ISO 8601 date: '#{val}'" + os.time :year, :month, :day + } + { + inp: 'URL -> image/.+', + out: 'mmm/dom', + cost: 1 + transform: (src, fileder) => img :src + } + { + inp: 'URL -> video/.+', + out: 'mmm/dom', + cost: 1 + transform: (src) => + -- @TODO: add parsed MIME type + video (source :src), controls: true, loop: true + } + { + inp: 'text/plain', + out: 'mmm/dom', + cost: 2 + transform: (val) => span val + } + { + inp: 'alpha', + out: 'mmm/dom', + cost: 2 + transform: single code + } + -- this one needs a higher cost + -- { + -- inp: 'URL -> .+', + -- out: 'mmm/dom', + -- transform: single code + -- } + { + inp: '(.+)', + out: 'URL -> %1', + cost: 5 + transform: (_, fileder, key) => "#{fileder.path}/#{key.name}:#{@from}" + } + { + inp: 'table', + out: 'text/json', + cost: 2 + transform: do + tojson = (obj) -> + switch type obj + when 'string' + string.format '%q', obj + when 'table' + if obj[1] or not next obj + "[#{table.concat [tojson c for c in *obj], ','}]" + else + "{#{table.concat ["#{tojson k}: #{tojson v}" for k,v in pairs obj], ', '}}" + when 'number' + tostring obj + when 'boolean' + tostring obj + when 'nil' + 'null' + else + error "unknown type '#{type obj}'" + + (val) => tojson val + } + { + inp: 'table', + out: 'mmm/dom', + cost: 5 + transform: do + deep_tostring = (tbl, space='') -> + buf = space .. tostring tbl + + return buf unless 'table' == type tbl + + buf = buf .. ' {\n' + for k,v in pairs tbl + buf = buf .. "#{space} [#{k}]: #{deep_tostring v, space .. ' '}\n" + buf = buf .. "#{space}}" + buf + + (tbl) => pre code deep_tostring tbl + } +} + +add_converts = (module) -> + ok, plugin = pcall require, ".plugins.#{module}" + + if not ok + print "[Plugins] couldn't load plugins.#{module}: #{plugin}" + return + + print "[Plugins] loaded plugins.#{module}" + + if plugin.converts + for convert in *plugin.converts + table.insert converts, convert + +add_converts 'code' +add_converts 'markdown' +add_converts 'mermaid' +add_converts 'twitter' +add_converts 'youtube' + +if MODE == 'SERVER' + ok, moon = pcall require, 'moonscript.base' + if ok + _load = moon.load or moon.loadstring + table.insert converts, { + inp: 'text/moonscript -> (.+)', + out: '%1', + cost: 1 + transform: loadwith moon.load or moon.loadstring + } + + table.insert converts, { + inp: 'text/moonscript -> (.+)', + out: 'text/lua -> %1', + cost: 2 + transform: single moon.to_lua + } +else + table.insert converts, { + inp: 'text/javascript -> (.+)', + out: '%1', + cost: 1 + transform: (source) => + f = js.new window.Function, source + f! + } + +:converts diff --git a/mmm/mmmfs/plugins/markdown.moon b/mmm/mmmfs/plugins/markdown.moon new file mode 100644 index 0000000..5024320 --- /dev/null +++ b/mmm/mmmfs/plugins/markdown.moon @@ -0,0 +1,33 @@ +markdown = if MODE == 'SERVER' + success, discount = pcall require, 'discount' + assert success, "couldn't require 'discount'" + + (md) -> + res = assert discount.compile md, 'githubtags' + res.body +else + assert window and window.marked, "marked.js not found" + window\marked + +assert markdown, "no markdown implementation found" + +{ + converts: { + { + inp: 'text/markdown' + out: 'text/html+frag' + cost: 1 + transform: (md) => "
#{markdown md}
" + } + { + inp: 'text/markdown%+span' + out: 'text/html+frag' + cost: 1 + transform: (source) => + html = markdown source + html = html\gsub '^%s*

%s*', '' + html = html\gsub '%s*

%s*$', '' + html + } + } +} diff --git a/mmm/mmmfs/plugins/mermaid.moon b/mmm/mmmfs/plugins/mermaid.moon new file mode 100644 index 0000000..ae34afa --- /dev/null +++ b/mmm/mmmfs/plugins/mermaid.moon @@ -0,0 +1,29 @@ +assert window and window.mermaid, "mermaid.js not found" + +window.mermaid\initialize { + startOnLoad: false + fontFamily: 'monospace' +} + +id_counter = 1 + +{ + converts: { + { + inp: 'text/mermaid-graph' + out: 'mmm/dom' + cost: 1 + transform: (source, fileder, key) => + id_counter += 1 + id = "mermaid-#{id_counter}" + with container = document\createElement 'div' + cb = (svg) => + .innerHTML = svg + .firstElementChild.style.width = '100%' + .firstElementChild.style.height = 'auto' + + window\setImmediate (_) -> + window.mermaid\render id, source, cb, container + } + } +} diff --git a/mmm/mmmfs/plugins/twitter.moon b/mmm/mmmfs/plugins/twitter.moon new file mode 100644 index 0000000..b6e1adc --- /dev/null +++ b/mmm/mmmfs/plugins/twitter.moon @@ -0,0 +1,22 @@ +import div, blockquote, a from require 'mmm.dom' + +{ + converts: { + { + inp: 'URL -> twitter/tweet' + out: 'mmm/dom' + cost: 1 + transform: (href) => + id = assert (href\match 'twitter.com/[^/]-/status/(%d*)'), "couldn't parse twitter/tweet URL: '#{href}'" + if MODE == 'CLIENT' + with parent = div! + window.twttr.widgets\createTweet id, parent + else + div blockquote { + class: 'twitter-tweet' + 'data-lang': 'en' + a '(linked tweet)', :href + } + } + } +} diff --git a/mmm/mmmfs/plugins/youtube.moon b/mmm/mmmfs/plugins/youtube.moon new file mode 100644 index 0000000..99cf995 --- /dev/null +++ b/mmm/mmmfs/plugins/youtube.moon @@ -0,0 +1,27 @@ +import iframe from require 'mmm.dom' + +{ + converts: { + { + inp: 'URL -> youtube/video' + out: 'mmm/dom' + cost: 1 + transform: (link) => + id = link\match 'youtu%.be/([^/]+)' + id or= link\match 'youtube.com/watch.*[?&]v=([^&]+)' + id or= link\match 'youtube.com/[ev]/([^/]+)' + id or= link\match 'youtube.com/embed/([^/]+)' + + assert id, "couldn't parse youtube URL: '#{link}'" + + iframe { + width: 560 + height: 315 + frameborder: 0 + allowfullscreen: true + frameBorder: 0 + src: "//www.youtube.com/embed/#{id}" + } + } + } +} -- cgit v1.2.3 From 28653c9ae46b2b3e42c2c75879589138c731f37b Mon Sep 17 00:00:00 2001 From: s-ol Date: Sun, 27 Oct 2019 20:22:00 +0100 Subject: facet editing with CodeMirror! --- build/server.moon | 5 ++++ mmm/mmmfs/browser.moon | 39 ++++++++++++------------ mmm/mmmfs/fileder.moon | 4 +-- mmm/mmmfs/plugins/code.moon | 48 +++++++++++++++++++++++++++++- mmm/mmmfs/plugins/init.moon | 18 +++++++----- scss/_browser.scss | 2 +- scss/_footer.scss | 1 + scss/codemirror.scss | 72 +++++++++++++++++++++++++++++++++++++++++++++ scss/main.scss | 1 + 9 files changed, 160 insertions(+), 30 deletions(-) create mode 100644 scss/codemirror.scss diff --git a/build/server.moon b/build/server.moon index 33853c9..906f89a 100644 --- a/build/server.moon +++ b/build/server.moon @@ -64,6 +64,11 @@ class Server + + + + + diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index 35925d3..b63010b 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -1,9 +1,9 @@ require = relative ..., 1 import Key from require '.fileder' -import converts from require '.plugins' +import converts, editors from require '.plugins' import get_conversions, apply_conversions from require '.conversion' import ReactiveVar, get_or_create, text, elements, tohtml from require 'mmm.component' -import pre, div, nav, span, button, a, code, select, option from elements +import pre, div, nav, span, button, a, code, option from elements import languages from require 'mmm.highlighting' keep = (var) -> @@ -12,15 +12,16 @@ keep = (var) -> last = val or last last +combine = (...) -> + res = {} + lists = {...} + for list in *lists + for val in *list + table.insert res, val + + res + casts = { - { - inp: 'text/.*', - out: 'mmm/dom', - cost: 0 - transform: (val) => - lang = @from\match 'text/(.*)' - languages[lang] val - } { inp: 'URL.*' out: 'mmm/dom' @@ -28,9 +29,7 @@ casts = { transform: (href) => span a (code href), :href } } - -for convert in *converts - table.insert casts, convert +casts = combine casts, converts, editors export BROWSER class Browser @@ -128,7 +127,7 @@ class Browser current = @facet\get! current = current and current.name - with select :onchange, disabled: not fileder, value: @facet\map (f) -> f and f.name + with elements.select :onchange, disabled: not fileder, value: @facet\map (f) -> f and f.name has_main = fileder and fileder\has_facet '' \append option '(main)', value: '', disabled: not has_main, selected: current == '' if fileder @@ -146,11 +145,11 @@ class Browser -- append or patch #browser-content main\append with get_or_create 'div', 'browser-content', class: 'content' - content = ReactiveVar if rehydrate then .node.lastChild else @get_content @facet\get! - \append keep content + @content = ReactiveVar if rehydrate then .node.lastChild else @get_content @facet\get! + \append keep @content if MODE == 'CLIENT' @facet\subscribe (p) -> - window\setTimeout (-> content\set @get_content p), 150 + window\setTimeout (-> @refresh p), 150 if rehydrate -- force one rerender to set onclick handlers etc @@ -166,6 +165,10 @@ class Browser err_and_trace = (msg) -> debug.traceback msg, 2 default_convert = (key) => @get key.name, 'mmm/dom' + -- rerender main content + refresh: (facet=@facet\get!) => + @content\set @get_content facet + -- render #browser-content get_content: (prop, err=@error, convert=default_convert) => clear_error = -> @@ -218,7 +221,7 @@ class Browser { :name } = @facet\get! @inspect_prop\set Key e.target.value - with select :onchange + with elements.select :onchange \append option '(none)', value: '', disabled: true, selected: not value if fileder for value in pairs fileder.facet_keys diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index cdfc649..f545bd8 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -134,8 +134,8 @@ class Fileder rawset t, k, v - v = k unless v == nil - @facet_keys[k] = v + if not v + @facet_keys[k] = nil } -- this fails with JS objects from JSON.parse diff --git a/mmm/mmmfs/plugins/code.moon b/mmm/mmmfs/plugins/code.moon index ec22f71..3024c99 100644 --- a/mmm/mmmfs/plugins/code.moon +++ b/mmm/mmmfs/plugins/code.moon @@ -1,6 +1,42 @@ -import pre from require 'mmm.dom' +import div from require 'mmm.dom' import languages from require 'mmm.highlighting' +class Editor + o = do + mkobj = window\eval "(function () { return {}; })" + (tbl) -> + with obj = mkobj! + for k,v in pairs(tbl) + obj[k] = v + + new: (value, mode, @fileder, @key) => + @node = div class: 'editor' + @cm = window\CodeMirror @node, o { + :value + :mode + lineNumber: true + lineWrapping: true + autoRefresh: true + theme: 'hybrid' + } + + @cm\on 'changes', (_, mirr) -> + window\clearTimeout @timeout if @timeout + @timeout = window\setTimeout (-> @change!), 300 + + change: => + @timeout = nil + doc = @cm\getDoc! + if @lastState and doc\isClean @lastState + -- no changes since last event + return + + @lastState = doc\changeGeneration true + value = doc\getValue! + + @fileder.facets[@key] = value + BROWSER\refresh! + -- syntax-highlighted code { converts: { @@ -13,4 +49,14 @@ import languages from require 'mmm.highlighting' pre languages[lang] val } } + editors: if MODE == 'CLIENT' then { + { + inp: 'text/([^ ]*).*' + out: 'mmm/dom' + cost: 0 + transform: (value, fileder, key) => + mode = @from\match @convert.inp + Editor value, mode, fileder, key + } + } } diff --git a/mmm/mmmfs/plugins/init.moon b/mmm/mmmfs/plugins/init.moon index af4a2aa..12fb061 100644 --- a/mmm/mmmfs/plugins/init.moon +++ b/mmm/mmmfs/plugins/init.moon @@ -4,12 +4,6 @@ import find_fileder, link_to, embed from (require 'mmm.mmmfs.util') require 'mmm import render from require '.layout' import tohtml from require 'mmm.component' -keep = (var) -> - last = var\get! - var\map (val) -> - last = val or last - last - -- fix JS null values js_fix = if MODE == 'CLIENT' (arg) -> @@ -24,13 +18,14 @@ loadwith = (_load) -> (val, fileder, key) => func = assert _load val, "#{fileder}##{key}" func! --- list of converts +-- list of converts, editors -- converts each have -- * inp - input type. can capture subtypes using `(.+)` -- * out - output type. can substitute subtypes from inp with %1, %2 etc. -- * cost - conversion cost -- * transform - function (val: inp, fileder) => val: out -- @convert, @from, @to contain the convert and the concrete types +editors = {} converts = { { inp: 'fn -> (.+)', @@ -256,6 +251,10 @@ add_converts = (module) -> for convert in *plugin.converts table.insert converts, convert + if plugin.editors + for editor in *plugin.editors + table.insert editors, editor + add_converts 'code' add_converts 'markdown' add_converts 'mermaid' @@ -289,4 +288,7 @@ else f! } -:converts +{ + :converts + :editors +} diff --git a/scss/_browser.scss b/scss/_browser.scss index b9910e8..b843916 100644 --- a/scss/_browser.scss +++ b/scss/_browser.scss @@ -15,7 +15,7 @@ &.inspector { top: 0; position: sticky; - max-height: 100vh; + max-height: calc(100vh - 3rem); color: #c5c8c6; @include left-border; diff --git a/scss/_footer.scss b/scss/_footer.scss index 727ebda..4f1c8bd 100644 --- a/scss/_footer.scss +++ b/scss/_footer.scss @@ -1,6 +1,7 @@ footer { display: flex; padding: 1rem 2rem; + height: 1rem; position: sticky; bottom: 0; diff --git a/scss/codemirror.scss b/scss/codemirror.scss new file mode 100644 index 0000000..1967f8c --- /dev/null +++ b/scss/codemirror.scss @@ -0,0 +1,72 @@ +/* + vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid) +*/ + +/*background color*/ +.CodeMirror.cm-s-hybrid { + color: #c5c8c6; + background: #1d1f21; + + height: auto; + + /*selection color*/ + .CodeMirror-selected, + .CodeMirror-line::selection, + .CodeMirror-line > span::selection, + .CodeMirror-line > span > span::selection, { + background: #373b41; + } + + /*foreground color*/ + .CodeMirror-cursor { + border-color: #c5c8c6; + } + + /*color: fg_yellow*/ + .cm-keyword { + color: #f0c674; + } + + /*color: fg_comment*/ + .cm-comment, + .cm-meta { + color: #707880; + } + + /*color: fg_red*/ + .cm-number, + .cm-atom { + color: #cc6666 + } + + /*color: fg_green*/ + .cm-string, + .cm-string-2, + .cm-operator { + color: #b5bd68; + } + + /*color: fg_purple*/ + .cm-attribute, + .cm-propery { + color: #b294bb; + } + + /*color: fg_blue*/ + .cm-tag, + .cm-qualifier { + color: #81a2be; + } + + /*color: fg_aqua*/ + .cm-link, + .cm-header, + .cm-hr { + color: #8abeb7; + } + + /*color: fg_orange*/ + .cm-builtin, { + color: #de935f; + } +} diff --git a/scss/main.scss b/scss/main.scss index c1e9d38..08ce942 100644 --- a/scss/main.scss +++ b/scss/main.scss @@ -1,6 +1,7 @@ @import 'defs'; @import 'reset'; @import 'hljs'; +@import 'codemirror'; @import 'header'; @import 'footer'; @import 'browser'; -- cgit v1.2.3 From 4b0c3714124f0d7c9c756f9c14bbc9e4b695ab49 Mon Sep 17 00:00:00 2001 From: s-ol Date: Sun, 27 Oct 2019 21:57:56 +0100 Subject: add ba_log entry 2019-10-26 --- .../mmmfs/ba_log/2019-10-26/text$markdown.md | 62 ++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 root/articles/mmmfs/ba_log/2019-10-26/text$markdown.md diff --git a/root/articles/mmmfs/ba_log/2019-10-26/text$markdown.md b/root/articles/mmmfs/ba_log/2019-10-26/text$markdown.md new file mode 100644 index 0000000..d5cd9bd --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-10-26/text$markdown.md @@ -0,0 +1,62 @@ +Besides some smaller fixes with the styling of the page, and in particular the diagrams introduced in [`2019-10-24`][2019-10-24], +I finally (re-)implemented children-ordering in the `fs`-store of mmmmfs +(the `sql` store is still missing it, but I am not currently using it either) \[[`a62f63b`][a62f63b]\]: +Files on the regular filesystem don't have a particular order, but in mmmfs the order of children is is guaranteed, +so that arranging children in a particular order becomes a meaningful tool. + +To store the ordering data, a 'magic' file called `$order` is (optionally) stored in each directory in the filesystem. +The file lists all child fileders by name in the given order. +When the children of a fileder are requested (in `list_fileders_in` or `get_index`, which relies on the former), +all children that are mentioned in `$order` are returned in that order, +while all remaining children are sorted alphabetically and appended at the end of the list. +This way the order is guaranteed to be stable even if no `$order` file is specified, +or when the `$order` file has not been updated after adding new children. + +Here is the commented implementation in MoonScript: + + list_fileders_in: (path='') => + -- create a mapping of all child-fileders + -- in 'entries' (name -> path) + entries = {} + for entry_name in lfs.dir @root .. path + continue if '.' == entry_name\sub 1, 1 + entry_path = @root .. "#{path}/#{entry_name}" + if 'directory' ~= lfs.attributes entry_path, 'mode' + continue + + entries[entry_name] = "#{path}/#{entry_name}" + + -- where we will store our sorted list of children + sorted = {} + + -- check for existance of the order file + order_file = @root .. "#{path}/$order" + if 'file' == lfs.attributes order_file, 'mode' + for line in io.lines order_file + path = assert entries[line], "entry in $order but not on disk: #{line}" + + -- add all $order-entries to the sorted output in the same order they appear. + -- also flag these entries as already added + table.insert sorted, path + sorted[line] = true + + -- find the he remaining (non-flagged) entries, sort them alphabetically + -- and then append them to the sorted output list + entries = [path for entry, path in pairs entries when not sorted[entry]] + table.sort entries + for path in *entries + table.insert sorted, path + + -- return an iterator over the sorted output + coroutine.wrap -> + for path in *sorted + coroutine.yield path + +The interface for reordering fileders is still missing in the code, +and just while writing this I realized that the current implementation is in fact buggy: +when a fileder that is mentioned in `$order` is deleted via the `stores.fs` API, +it is not removed from `$order`, causing an error the next time the fileder is listed. +I will probably get around to fixing both of these problems when I build the corresponding UI. + +[2019-10-24]: /articles/mmmfs/ba_log/2019-10-24/ +[a62f63b]: https://git.s-ol.nu/mmm/commit/a62f63bc00cd63a98b349a2574e3e9e14c95a441/ -- cgit v1.2.3 From 99f1cc5015357f836b6d9e414f52fc1d5a79abbf Mon Sep 17 00:00:00 2001 From: s-ol Date: Sun, 27 Oct 2019 22:22:52 +0100 Subject: add ba_log entry 2019-10-27 --- .../mmmfs/ba_log/2019-10-27/text$markdown.md | 75 +++++++++++++++++++++ .../mmmfs/ba_log/2019-10-27/video/video$webm.webm | Bin 0 -> 5209109 bytes 2 files changed, 75 insertions(+) create mode 100644 root/articles/mmmfs/ba_log/2019-10-27/text$markdown.md create mode 100644 root/articles/mmmfs/ba_log/2019-10-27/video/video$webm.webm diff --git a/root/articles/mmmfs/ba_log/2019-10-27/text$markdown.md b/root/articles/mmmfs/ba_log/2019-10-27/text$markdown.md new file mode 100644 index 0000000..752c355 --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-10-27/text$markdown.md @@ -0,0 +1,75 @@ +Today I finally reached the ability of editing content inside of mmmfs directly! + + + +Content is currently not saved anywhere, but the basis of the feature is there. +For the moment this is implemented as yeat another *convert* that simply converts +from `text/.*` (any textual code) to `mmm/dom` (web UI) \[[`28653c9`][28653c9]\]. +However this *convert* is only applied in the inspector view (more on that below). +First, here is the convert itself: + + { + inp: 'text/([^ ]*).*' + out: 'mmm/dom' + cost: 0 + transform: (value, fileder, key) => + mode = @from\match @convert.inp + Editor value, mode, fileder, key + } + +and the main part of the code, the `Editor` widget: + + class Editor + new: (value, mode, @fileder, @key) => + @node = div class: 'editor' + -- 'o' is a little helper for converting a Lua table to a JS object + @cm = window\CodeMirror @node, o { + :value + :mode + lineNumber: true + lineWrapping: true + autoRefresh: true + theme: 'hybrid' + } + + @cm\on 'changes', (_, mirr) -> + window\clearTimeout @timeout if @timeout + @timeout = window\setTimeout (-> @change!), 300 + + change: => + @timeout = nil + doc = @cm\getDoc! + if @lastState and doc\isClean @lastState + -- no changes since last event + return + + @lastState = doc\changeGeneration true + value = doc\getValue! + + @fileder.facets[@key] = value + BROWSER\refresh! + +I chose the [CodeMirror][codemirror] library as the basis for the editor, +because it seemed like one of the leanest ones I could find +(and yet it is quite heavy at 100kb plus styling and language support addons). +The code for the editor is also quite minimale it really just creates a wrapper for the editor +and tells CodeMirror to set itself up inside. +Whenever changes are detected, a timeout of 300ms is started, +after which the preview is refreshed to preview the changes. +If more changes are made within the 300ms, the timer is reset to 300ms, +so that the preview update doesn't interrupt the typing flow. + +I also spent some time refactoring the global list of converts out into multiple smaller plugins +(although a lot of global converts remain at the moment) \[[`abefbf8`][abefbf8]\]. +A plugin can export a list of converts as well as a list of 'editors', which are essentially no different, +except that they are taken into consideration only when converting content for the inspector. + +Breaking the converts up into little packages like that makes it a lot easier to edit, +and allows enabling and disabling individual features very easily. +I am also considering moving the converts into the mmmfs data itself, +to make extending the system and working inside the system more congruent, +and this is a good way of testing my idea of how the modularization of the system should work. + +[codemirror]: https://codemirror.net/ +[28653c9]: https://git.s-ol.nu/mmm/commit/28653c9ae46b2b3e42c2c75879589138c731f37b/ +[abefbf8]: https://git.s-ol.nu/mmm/commit/abefbf82531021f5ca4149675932a7fe2ff37dde/ diff --git a/root/articles/mmmfs/ba_log/2019-10-27/video/video$webm.webm b/root/articles/mmmfs/ba_log/2019-10-27/video/video$webm.webm new file mode 100644 index 0000000..020e352 Binary files /dev/null and b/root/articles/mmmfs/ba_log/2019-10-27/video/video$webm.webm differ -- cgit v1.2.3 From 78a90d184f0b186164b41e07dc0ce3891420c99d Mon Sep 17 00:00:00 2001 From: s-ol Date: Sat, 26 Oct 2019 21:36:51 +0200 Subject: fix the damn text width problem, once and for all ???? --- scss/_browser.scss | 5 +++++ scss/_content.scss | 16 +++++++++++++--- scss/_defs.scss | 1 + scss/_reset.scss | 2 +- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/scss/_browser.scss b/scss/_browser.scss index b843916..da49f71 100644 --- a/scss/_browser.scss +++ b/scss/_browser.scss @@ -30,6 +30,7 @@ margin: 0; padding: 0; display: flex; + align-self: stretch; background: $gray-darker; > * { @@ -101,6 +102,10 @@ flex: 1 1 auto; overflow: auto; padding: 1em 2em; + margin: 0 1em; + align-self: flex-start; + min-width: 30vw; + background: var(--white); position: relative; } diff --git a/scss/_content.scss b/scss/_content.scss index 66b9f42..6993fef 100644 --- a/scss/_content.scss +++ b/scss/_content.scss @@ -4,11 +4,17 @@ height: inherit; } + .markdown { + max-width: 640px; + position: relative; + } + .markdown, .markdown > p, - .markdown > p > a, - .markdown > a { - max-width: 100%; + .markdown > p > a { + p, a { + max-width: 100%; + } > img, > video { display: block; @@ -39,6 +45,10 @@ margin: 0.2em; background: $gray-bright; } + + > *:not(.description) { + max-width: 100%; + } } pre > code { diff --git a/scss/_defs.scss b/scss/_defs.scss index 7806420..40804b2 100644 --- a/scss/_defs.scss +++ b/scss/_defs.scss @@ -22,6 +22,7 @@ $break-large: 768px; } :root { + --white: #{$white}; --gray-bright: #{$gray-bright}; --gray-dark: #{$gray-dark}; --gray-darker: #{$gray-darker}; diff --git a/scss/_reset.scss b/scss/_reset.scss index 0f4fa6e..859f96f 100644 --- a/scss/_reset.scss +++ b/scss/_reset.scss @@ -27,7 +27,7 @@ body { flex-direction: column; justify-content: space-between; - background: $white; + background: var(--gray-bright); font-family: sans-serif; min-height: 100vh; -- cgit v1.2.3 From da4d5283a6cb563758ff3678d98e9358c53266d7 Mon Sep 17 00:00:00 2001 From: s-ol Date: Sun, 27 Oct 2019 22:58:35 +0100 Subject: fix syntax highlighting in markdown --- mmm/mmmfs/plugins/code.moon | 2 +- mmm/mmmfs/plugins/markdown.moon | 26 ++++++++++- .../mmmfs/ba_log/2019-10-27/text$markdown.md | 54 +++++++++++----------- 3 files changed, 54 insertions(+), 28 deletions(-) diff --git a/mmm/mmmfs/plugins/code.moon b/mmm/mmmfs/plugins/code.moon index 3024c99..c3c6c50 100644 --- a/mmm/mmmfs/plugins/code.moon +++ b/mmm/mmmfs/plugins/code.moon @@ -2,7 +2,7 @@ import div from require 'mmm.dom' import languages from require 'mmm.highlighting' class Editor - o = do + o = if MODE == 'CLIENT' mkobj = window\eval "(function () { return {}; })" (tbl) -> with obj = mkobj! diff --git a/mmm/mmmfs/plugins/markdown.moon b/mmm/mmmfs/plugins/markdown.moon index 5024320..afa0307 100644 --- a/mmm/mmmfs/plugins/markdown.moon +++ b/mmm/mmmfs/plugins/markdown.moon @@ -3,10 +3,34 @@ markdown = if MODE == 'SERVER' assert success, "couldn't require 'discount'" (md) -> - res = assert discount.compile md, 'githubtags' + res = assert discount.compile md, 'githubtags', 'fencedcode' res.body else assert window and window.marked, "marked.js not found" + + o = do + mkobj = window\eval "(function () { return {}; })" + (tbl) -> + with obj = mkobj! + for k,v in pairs(tbl) + obj[k] = v + + trim = (str) -> str\match '^ *(..-) *$' + + window.marked\setOptions o { + gfm: true + smartypants: true + langPrefix: 'lang-' + highlight: (code, lang) => + code = trim code + result = if lang and #lang > 0 + window.hljs\highlight lang, code, true + else + window.hljs\highlightAuto code + + result.value + } + window\marked assert markdown, "no markdown implementation found" diff --git a/root/articles/mmmfs/ba_log/2019-10-27/text$markdown.md b/root/articles/mmmfs/ba_log/2019-10-27/text$markdown.md index 752c355..3e9f886 100644 --- a/root/articles/mmmfs/ba_log/2019-10-27/text$markdown.md +++ b/root/articles/mmmfs/ba_log/2019-10-27/text$markdown.md @@ -19,35 +19,37 @@ First, here is the convert itself: and the main part of the code, the `Editor` widget: - class Editor - new: (value, mode, @fileder, @key) => - @node = div class: 'editor' - -- 'o' is a little helper for converting a Lua table to a JS object - @cm = window\CodeMirror @node, o { - :value - :mode - lineNumber: true - lineWrapping: true - autoRefresh: true - theme: 'hybrid' - } +```moonscript +class Editor + new: (value, mode, @fileder, @key) => + @node = div class: 'editor' + -- 'o' is a little helper for converting a Lua table to a JS object + @cm = window\CodeMirror @node, o { + :value + :mode + lineNumber: true + lineWrapping: true + autoRefresh: true + theme: 'hybrid' + } - @cm\on 'changes', (_, mirr) -> - window\clearTimeout @timeout if @timeout - @timeout = window\setTimeout (-> @change!), 300 + @cm\on 'changes', (_, mirr) -> + window\clearTimeout @timeout if @timeout + @timeout = window\setTimeout (-> @change!), 300 - change: => - @timeout = nil - doc = @cm\getDoc! - if @lastState and doc\isClean @lastState - -- no changes since last event - return - - @lastState = doc\changeGeneration true - value = doc\getValue! + change: => + @timeout = nil + doc = @cm\getDoc! + if @lastState and doc\isClean @lastState + -- no changes since last event + return + + @lastState = doc\changeGeneration true + value = doc\getValue! - @fileder.facets[@key] = value - BROWSER\refresh! + @fileder.facets[@key] = value + BROWSER\refresh! +``` I chose the [CodeMirror][codemirror] library as the basis for the editor, because it seemed like one of the leanest ones I could find -- cgit v1.2.3 From 4b8d9be10e4517114c0c216fa24aaaa310503d4a Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 29 Oct 2019 12:52:56 +0100 Subject: save edited changes --- build/server.moon | 86 ++++++++++++++++++++++++++------------------- mmm/mmmfs/fileder.moon | 15 ++++++++ mmm/mmmfs/layout.moon | 12 +++---- mmm/mmmfs/plugins/code.moon | 41 ++++++++++++++++++--- mmm/mmmfs/stores/init.moon | 15 ++++++++ mmm/mmmfs/stores/web.moon | 28 +++++++++------ scss/codemirror.scss | 1 + 7 files changed, 138 insertions(+), 60 deletions(-) diff --git a/build/server.moon b/build/server.moon index 906f89a..68cf4db 100644 --- a/build/server.moon +++ b/build/server.moon @@ -38,7 +38,43 @@ class Server print "[#{@@__name}]", "running at #{ip}:#{port}" assert @server\loop! - handle: (method, path, facet) => + handle_interactive: (fileder, facet) => + root = Fileder @store + browser = Browser root, fileder.path, facet.name + + deps = [[ + + + + + + + + + + + ]] + + render browser\todom!, fileder, noview: true, scripts: deps .. " + " + + handle: (method, path, facet, value) => fileder = Fileder @store, path if not fileder @@ -57,41 +93,7 @@ class Server convert 'table', facet.type, index, fileder, facet.name else if facet.type == 'text/html+interactive' - root = Fileder @store - browser = Browser root, path, facet.name - - deps = [[ - - - - - - - - - - - - ]] - - render browser\todom!, fileder, noview: true, scripts: deps .. " - " + @handle_interactive fileder, facet else if not fileder\has_facet facet.name 404, "facet '#{facet.name}' not found in fileder '#{path}'" else @@ -101,6 +103,15 @@ class Server 200, val else 406, "cant convert facet '#{facet.name}' to '#{facet.type}'" + when 'POST' + @store\create_facet path, facet.name, facet.type, value + 200, 'ok' + when 'PUT' + @store\update_facet path, facet.name, facet.type, value + 200, 'ok' + when 'DELETE' + @store\remove_facet path, facet.name, facet.type + 200, 'ok' else 501, "not implemented" @@ -119,7 +130,8 @@ class Server type = type\match '%s*(.*)' facet = Key facet, type - ok, status, body = xpcall @.handle, err_and_trace, @, method, path, facet + value = stream\get_body_as_string! + ok, status, body = xpcall @.handle, err_and_trace, @, method, path, facet, value if not ok warn "Error handling request (#{method} #{path} #{facet}):\n#{status}" body = "Internal Server Error:\n#{status}" diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index f545bd8..5b65496 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -278,6 +278,21 @@ class Fileder assert value, "#{@} doesn't have value for '#{want}'" value, key + -- set a facet value and propagate to the store + set: (key, key2, value) => + if value + key = Key key, key2 + else + key = Key key + value = key2 + + if @facet_keys[key] + @store\update_facet @path, key.name, key.type, value + else + @store\create_facet @path, key.name, key.type, value + + @facets[key] = value + __tostring: => "Fileder:#{@path}" { diff --git a/mmm/mmmfs/layout.moon b/mmm/mmmfs/layout.moon index 05bc38b..7fd3091 100644 --- a/mmm/mmmfs/layout.moon +++ b/mmm/mmmfs/layout.moon @@ -130,8 +130,7 @@ render = (content, fileder, opts={}) -> - - ]] + ]] buf ..= " #{get_meta fileder} @@ -140,19 +139,16 @@ render = (content, fileder, opts={}) -> #{content} - #{footer} - " + #{footer}" buf ..= [[ - - ]] + ]] buf ..= opts.scripts buf ..= " - - " +" buf diff --git a/mmm/mmmfs/plugins/code.moon b/mmm/mmmfs/plugins/code.moon index c3c6c50..bd28c79 100644 --- a/mmm/mmmfs/plugins/code.moon +++ b/mmm/mmmfs/plugins/code.moon @@ -1,4 +1,4 @@ -import div from require 'mmm.dom' +import div, button from require 'mmm.dom' import languages from require 'mmm.highlighting' class Editor @@ -10,7 +10,27 @@ class Editor obj[k] = v new: (value, mode, @fileder, @key) => - @node = div class: 'editor' + @node = div { + class: 'editor' + style: + display: 'flex' + 'flex-direction': 'column' + 'justify-content': 'space-around' + + div { + style: + display: 'flex' + flex: '0' + 'justify-content': 'flex-end' + 'border-bottom': '2px solid var(--gray-dark)' + 'padding-bottom': '0.5em' + 'margin': '-0.5em 0 0.5em' + + with @saveBtn = button 'save changes' + .disabled = true + .onclick = (_, e) -> @save e + } + } @cm = window\CodeMirror @node, o { :value :mode @@ -20,23 +40,36 @@ class Editor theme: 'hybrid' } + @lastSave = @cm\getDoc!\changeGeneration true + @cm\on 'changes', (_, mirr) -> + doc = @cm\getDoc! + @saveBtn.disabled = doc\isClean @lastSave + window\clearTimeout @timeout if @timeout @timeout = window\setTimeout (-> @change!), 300 change: => @timeout = nil doc = @cm\getDoc! - if @lastState and doc\isClean @lastState + + if @lastPreview and doc\isClean @lastPreview -- no changes since last event return - @lastState = doc\changeGeneration true + @lastPreview = doc\changeGeneration! value = doc\getValue! @fileder.facets[@key] = value BROWSER\refresh! + save: (e) => + e\preventDefault! + + doc = @cm\getDoc! + @fileder\set @key, doc\getValue! + @lastSave = doc\changeGeneration true + -- syntax-highlighted code { converts: { diff --git a/mmm/mmmfs/stores/init.moon b/mmm/mmmfs/stores/init.moon index bbca33f..905188f 100644 --- a/mmm/mmmfs/stores/init.moon +++ b/mmm/mmmfs/stores/init.moon @@ -26,6 +26,21 @@ class Store children: [@get_index child, depth - 1 for child in @list_fileders_in path] } + create_fileder: => error "not implemented" + remove_fileder: => error "not implemented" + rename_fileder: => error "not implemented" + move_fileder: => error "not implemented" + + list_facets: => error "not implemented" + create_facet: => error "not implemented" + remove_facet: => error "not implemented" + load_facet: => error "not implemented" + rename_facet: (path, name, type, next_name) => + @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}" + blob = assert "no such facet", @load_facet path, name, type + @create_facet path, next_name, type, blob + @remove_facet path, name, type update_facet: => error "not implemented" + close: => log: (...) => diff --git a/mmm/mmmfs/stores/web.moon b/mmm/mmmfs/stores/web.moon index ea17b5a..ed3f6d7 100644 --- a/mmm/mmmfs/stores/web.moon +++ b/mmm/mmmfs/stores/web.moon @@ -10,10 +10,14 @@ dir_base = (path) -> dir, base -fetch = (url) -> +req = (method, url, content=js.null) -> + if not url + url = method + method = 'GET' + request = js.new XMLHttpRequest - request\open 'GET', url, false - request\send js.null + request\open method, url, false + request\send content assert request.status == 200, "unexpected status code: #{request.status}" request.responseText @@ -45,13 +49,13 @@ class WebStore extends Store get_index: (path='', depth=1) => pseudo = if depth > 1 or depth < 0 '?tree' else '?index' - json = fetch "#{@host .. path}/#{pseudo}: text/json" + json = req "#{@host .. path}/#{pseudo}: text/json" parse_json json -- fileders list_fileders_in: (path='') => coroutine.wrap -> - json = fetch "#{@host .. path}/?index: text/json" + json = req "#{@host .. path}/?index: text/json" index = parse_json json for child in js.of index.children coroutine.yield child.path @@ -75,30 +79,32 @@ class WebStore extends Store -- facets list_facets: (path) => coroutine.wrap -> - json = fetch "#{@host .. path}/?index: text/json" + json = req "#{@host .. path}/?index: text/json" index = JSON\parse json for facet in js.of index.facets coroutine.yield facet.name, facet.type load_facet: (path, name, type) => @log "loading facet #{path} #{name}: #{type}" - fetch "#{@host .. path}/#{name}: #{type}" + req "#{@host .. path}/#{name}: #{type}" create_facet: (path, name, type, blob) => @log "creating facet #{path} | #{name}: #{type}" - error "not implemented" + req 'POST', "#{@host .. path}/#{name}: #{type}", blob remove_facet: (path, name, type) => @log "removing facet #{path} | #{name}: #{type}" - error "not implemented" + req 'DELETE', "#{@host .. path}/#{name}: #{type}" rename_facet: (path, name, type, next_name) => @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}" - error "not implemented" + blob = assert "no such facet", @load_facet path, name, type + @create_facet path, next_name, type, blob + @remove_facet path, name, type update_facet: (path, name, type, blob) => @log "updating facet #{path} | #{name}: #{type}" - error "not implemented" + req 'PUT', "#{@host .. path}/#{name}: #{type}", blob { :WebStore diff --git a/scss/codemirror.scss b/scss/codemirror.scss index 1967f8c..fd50b00 100644 --- a/scss/codemirror.scss +++ b/scss/codemirror.scss @@ -8,6 +8,7 @@ background: #1d1f21; height: auto; + flex: 1; /*selection color*/ .CodeMirror-selected, -- cgit v1.2.3 From e0a96098143697821d66153acd0b8d0cf8acbb2a Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 29 Oct 2019 12:53:09 +0100 Subject: small styling fixes --- scss/_browser.scss | 1 + scss/_reset.scss | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/scss/_browser.scss b/scss/_browser.scss index da49f71..1c5b5b2 100644 --- a/scss/_browser.scss +++ b/scss/_browser.scss @@ -79,6 +79,7 @@ padding: 1em 2em; overflow: hidden; + color: $gray-darker; background: $gray-fail; &.empty { diff --git a/scss/_reset.scss b/scss/_reset.scss index 859f96f..396c3e7 100644 --- a/scss/_reset.scss +++ b/scss/_reset.scss @@ -13,7 +13,12 @@ body, html, h1, h2, h3, h4, h5, h6 { } h1, h2, h3, h4, h5, h6 { font-weight: bold; } -input, select, button { color: initial; } +input, select, button { + color: initial; + &:disabled { + color: graytext; + } +} tt, code, kbd, samp { font-family: monospace; } code { font-size: 0.8em; } b, strong { font-weight: bold; } -- cgit v1.2.3 From d9eafa21ad1d6ad340b5744d69e9fc68ce2083cb Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 29 Oct 2019 14:18:16 +0100 Subject: add sandbox --- Dockerfile | 2 +- build/server.moon | 16 ++++++++++++--- root/sandbox/description: text$markdown.md | 5 +++++ root/sandbox/dynamic-children/a/text$lua -> table | 0 root/sandbox/dynamic-children/b/text$markdown.md | 0 .../c/text$javascript -> text$markdown.js | 0 .../dynamic-children/description: text$markdown.md | 1 + .../dynamic-children/text$lua -> fn -> mmm$dom.lua | 19 +++++++++++++++++ .../javascript/description: text$markdown.md | 1 + .../javascript/text$javascript -> mmm$dom.js | 24 ++++++++++++++++++++++ root/sandbox/lua/description: text$markdown.md | 1 + root/sandbox/lua/text$lua -> mmm$dom.lua | 10 +++++++++ root/sandbox/text$lua -> fn -> mmm$dom.lua | 18 ++++++++++++++++ 13 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 root/sandbox/description: text$markdown.md create mode 100644 root/sandbox/dynamic-children/a/text$lua -> table create mode 100644 root/sandbox/dynamic-children/b/text$markdown.md create mode 100644 root/sandbox/dynamic-children/c/text$javascript -> text$markdown.js create mode 100644 root/sandbox/dynamic-children/description: text$markdown.md create mode 100644 root/sandbox/dynamic-children/text$lua -> fn -> mmm$dom.lua create mode 100644 root/sandbox/javascript/description: text$markdown.md create mode 100644 root/sandbox/javascript/text$javascript -> mmm$dom.js create mode 100644 root/sandbox/lua/description: text$markdown.md create mode 100644 root/sandbox/lua/text$lua -> mmm$dom.lua create mode 100644 root/sandbox/text$lua -> fn -> mmm$dom.lua diff --git a/Dockerfile b/Dockerfile index ef1246b..f95ac67 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,4 +16,4 @@ WORKDIR /code RUN tup init && tup generate --config tup.docker.config build-static.sh && ./build-static.sh EXPOSE 8000 -ENTRYPOINT ["moon", "build/server.moon", "fs", "0.0.0.0", "8000"] +ENTRYPOINT ["moon", "build/server.moon", "fs", "0.0.0.0", "8000", "^/sandbox/"] diff --git a/build/server.moon b/build/server.moon index 68cf4db..d101d0b 100644 --- a/build/server.moon +++ b/build/server.moon @@ -29,6 +29,8 @@ class Server opts.onstream = @\stream opts.onerror = @\error + @editable_paths = opts.editable_paths + @server = server.listen opts listen: => @@ -81,6 +83,10 @@ class Server -- fileder not found 404, "fileder '#{path}' not found" + if method != 'GET' and method != 'HEAD' + if not @editable_paths or not path\match @editable_paths + return 403, 'editing not allowed' + switch method when 'GET', 'HEAD' val = switch facet.name @@ -153,9 +159,13 @@ class Server msg = "#{msg}: #{err}" if err -- usage: --- moon server.moon [STORE] [host] [port] -{ store, host, port } = arg +-- moon server.moon [STORE] [host] [port] [editable-paths] +-- * STORE: see mmm/mmmfs/stores/init.moon:get_store +-- * host: interface to bind to (default localhost, set to 0.0.0.0 for public hosting) +-- * port: port to serve from, default 8000 +-- * editable-paths: Lua pattern to match paths in which editing is allowed, default none +{ store, host, port, editable_paths } = arg store = get_store store -server = Server store, :host, port: port and tonumber port +server = Server store, :host, :editable_paths, port: port and tonumber port server\listen! diff --git a/root/sandbox/description: text$markdown.md b/root/sandbox/description: text$markdown.md new file mode 100644 index 0000000..250bb4e --- /dev/null +++ b/root/sandbox/description: text$markdown.md @@ -0,0 +1,5 @@ +Everything in this Fileder is world-editable on the internet. +It will be reset to its' default state whenever I push my repository. +Please behave. + +Here is a list of this fileders content: diff --git a/root/sandbox/dynamic-children/a/text$lua -> table b/root/sandbox/dynamic-children/a/text$lua -> table new file mode 100644 index 0000000..e69de29 diff --git a/root/sandbox/dynamic-children/b/text$markdown.md b/root/sandbox/dynamic-children/b/text$markdown.md new file mode 100644 index 0000000..e69de29 diff --git a/root/sandbox/dynamic-children/c/text$javascript -> text$markdown.js b/root/sandbox/dynamic-children/c/text$javascript -> text$markdown.js new file mode 100644 index 0000000..e69de29 diff --git a/root/sandbox/dynamic-children/description: text$markdown.md b/root/sandbox/dynamic-children/description: text$markdown.md new file mode 100644 index 0000000..32216ce --- /dev/null +++ b/root/sandbox/dynamic-children/description: text$markdown.md @@ -0,0 +1 @@ +dynamically embedding children fileders with Lua diff --git a/root/sandbox/dynamic-children/text$lua -> fn -> mmm$dom.lua b/root/sandbox/dynamic-children/text$lua -> fn -> mmm$dom.lua new file mode 100644 index 0000000..a3a019b --- /dev/null +++ b/root/sandbox/dynamic-children/text$lua -> fn -> mmm$dom.lua @@ -0,0 +1,19 @@ +local d = require 'mmm.dom' +local u = require('mmm.mmmfs.util')(d) + +-- we need to return a function to get access to the current fileder +-- (thats why there is the '-> fn ->' in the type) +return function(self) + local children = {} + for i, child in ipairs(self.children) do + table.insert(children, d.li { + 'child ' .. i .. ': ', + u.link_to(child), + }) + end + + return d.article { + d.h1 'The Children are:', + d.ul(children), + } +end diff --git a/root/sandbox/javascript/description: text$markdown.md b/root/sandbox/javascript/description: text$markdown.md new file mode 100644 index 0000000..eb0ca7c --- /dev/null +++ b/root/sandbox/javascript/description: text$markdown.md @@ -0,0 +1 @@ +an example of how to use JS to create (dynamic) DOM / mmmfs content diff --git a/root/sandbox/javascript/text$javascript -> mmm$dom.js b/root/sandbox/javascript/text$javascript -> mmm$dom.js new file mode 100644 index 0000000..58deb23 --- /dev/null +++ b/root/sandbox/javascript/text$javascript -> mmm$dom.js @@ -0,0 +1,24 @@ +// a little helper function for creating DOM elements +const e = (elem, children) => { + const node = document.createElement(elem); + + if (typeof children === 'string') + node.innerText = children; + else + children.forEach(child => node.appendChild(child)); + + return node; +}; + +/* creating the equivalent of the following HTML directly as DOM content: + * + *
+ *

JavaScript

+ *

...

+ *
+ */ + +return e('article', [ + e('h1', 'JavaScript'), + e('p', 'JavaScript is supported natively in the browser but is not currently pre-rendered on the server.'), +]); diff --git a/root/sandbox/lua/description: text$markdown.md b/root/sandbox/lua/description: text$markdown.md new file mode 100644 index 0000000..3071697 --- /dev/null +++ b/root/sandbox/lua/description: text$markdown.md @@ -0,0 +1 @@ +an example of how to use Lua to create (dynamic) DOM / mmmfs content diff --git a/root/sandbox/lua/text$lua -> mmm$dom.lua b/root/sandbox/lua/text$lua -> mmm$dom.lua new file mode 100644 index 0000000..db420ce --- /dev/null +++ b/root/sandbox/lua/text$lua -> mmm$dom.lua @@ -0,0 +1,10 @@ +-- see /meta/mmm.dom for documentation +local d = require 'mmm.dom' + +local lua = d.a { 'Lua', href = 'https://www.lua.org/' } +local fengari = d.a { 'fengari.io', href = 'https://fengari.io/' } + +return d.article { + d.h1 'Lua', + d.p { lua, ' is fully supported using ', fengari, ' on the Client.' } +} diff --git a/root/sandbox/text$lua -> fn -> mmm$dom.lua b/root/sandbox/text$lua -> fn -> mmm$dom.lua new file mode 100644 index 0000000..18206bb --- /dev/null +++ b/root/sandbox/text$lua -> fn -> mmm$dom.lua @@ -0,0 +1,18 @@ +local d = require 'mmm.dom' +local u = require('mmm.mmmfs.util')(d) + +return function(self) + local children = {} + for i, child in ipairs(self.children) do + table.insert( + children, + d.li(u.link_to(child), ': ', (child:get('description: mmm/dom'))) + ) + end + + return d.div({ + d.h3(u.link_to(self)), + self:gett('description: mmm/dom'), + d.ul(children), + }) +end -- cgit v1.2.3 From 7303db4d32d692ad329cc6c6097cb9c79962dc5e Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 29 Oct 2019 14:19:29 +0100 Subject: fixes --- mmm/mmmfs/fileder.moon | 8 +++++++- mmm/mmmfs/plugins/code.moon | 2 +- mmm/mmmfs/stores/fs.moon | 7 +++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index 5b65496..9918adc 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -43,6 +43,12 @@ class Key __tostring: => @tostring! +-- stateless iterator for implementing __ipairs +inext = (tbl, i) -> + i += 1 + if v = tbl[i] + i, v + -- Fileder itself -- contains: -- * @facets - Facet Map (Key to Value) @@ -61,7 +67,7 @@ class Fileder __ipairs: (t) -> @load! unless @loaded - ipairs t + inext, t, 0 __index: (t, k) -> @load! unless @loaded diff --git a/mmm/mmmfs/plugins/code.moon b/mmm/mmmfs/plugins/code.moon index bd28c79..5a437b4 100644 --- a/mmm/mmmfs/plugins/code.moon +++ b/mmm/mmmfs/plugins/code.moon @@ -1,4 +1,4 @@ -import div, button from require 'mmm.dom' +import pre, div, button from require 'mmm.dom' import languages from require 'mmm.highlighting' class Editor diff --git a/mmm/mmmfs/stores/fs.moon b/mmm/mmmfs/stores/fs.moon index 8aeaf65..1e09d1d 100644 --- a/mmm/mmmfs/stores/fs.moon +++ b/mmm/mmmfs/stores/fs.moon @@ -133,17 +133,16 @@ class FSStore extends Store @log "creating facet #{path} | #{name}: #{type}" assert blob, "cant create facet without value!" - filepath = @tofp path, name, type - if lfs.attributes filepath, 'mode' - error "facet file already exists!" + filepath = @locate path, name, type + assert not filepath, "facet file already exists!" + filepath = @tofp path, name, type file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'" file\write blob file\close! remove_facet: (path, name, type) => @log "removing facet #{path} | #{name}: #{type}" - filepath = @locate path, name, type assert filepath, "couldn't locate facet!" assert os.remove filepath -- cgit v1.2.3 From 16402fb6702f296d400bddb81561710d6cb37b6f Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 29 Oct 2019 14:33:18 +0100 Subject: fix the glaring security vulnerability i just implemented --- build/server.moon | 5 +++++ mmm/mmmfs/plugins/init.moon | 27 +++++++++++++++------------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/build/server.moon b/build/server.moon index d101d0b..b219c58 100644 --- a/build/server.moon +++ b/build/server.moon @@ -21,6 +21,8 @@ lfs = require 'lfs' server = require 'http.server' headers = require 'http.headers' +export UNSAFE + class Server new: (@store, opts={}) => opts = {k,v for k,v in pairs opts} @@ -29,6 +31,9 @@ class Server opts.onstream = @\stream opts.onerror = @\error + if opts.host == 'localhost' + UNSAFE = true + @editable_paths = opts.editable_paths @server = server.listen opts diff --git a/mmm/mmmfs/plugins/init.moon b/mmm/mmmfs/plugins/init.moon index 12fb061..583fbb4 100644 --- a/mmm/mmmfs/plugins/init.moon +++ b/mmm/mmmfs/plugins/init.moon @@ -129,12 +129,6 @@ converts = { assert 1 == parent.childElementCount, "text/html with more than one child!" parent.firstElementChild } - { - inp: 'text/lua -> (.+)', - out: '%1', - cost: 0.5 - transform: loadwith load or loadstring - } { inp: 'mmm/tpl -> (.+)', out: '%1', @@ -238,6 +232,14 @@ converts = { } } +if MODE == 'CLIENT' or UNSAFE + table.insert converts, { + inp: 'text/lua -> (.+)', + out: '%1', + cost: 0.5 + transform: loadwith load or loadstring + } + add_converts = (module) -> ok, plugin = pcall require, ".plugins.#{module}" @@ -265,12 +267,13 @@ if MODE == 'SERVER' ok, moon = pcall require, 'moonscript.base' if ok _load = moon.load or moon.loadstring - table.insert converts, { - inp: 'text/moonscript -> (.+)', - out: '%1', - cost: 1 - transform: loadwith moon.load or moon.loadstring - } + if UNSAFE + table.insert converts, { + inp: 'text/moonscript -> (.+)', + out: '%1', + cost: 1 + transform: loadwith moon.load or moon.loadstring + } table.insert converts, { inp: 'text/moonscript -> (.+)', -- cgit v1.2.3 From 1e3b0a12060dce916b686921c94520202c4cb130 Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 29 Oct 2019 15:18:25 +0100 Subject: make security vulnerabilities optional, remove sandbox --- Dockerfile | 2 +- build/server.moon | 56 +++++++++++++++------- mmm/init.client.moon | 3 +- mmm/mmmfs/browser.moon | 5 +- root/sandbox/description: text$markdown.md | 5 -- root/sandbox/dynamic-children/a/text$lua -> table | 0 root/sandbox/dynamic-children/b/text$markdown.md | 0 .../c/text$javascript -> text$markdown.js | 0 .../dynamic-children/description: text$markdown.md | 1 - .../dynamic-children/text$lua -> fn -> mmm$dom.lua | 19 -------- .../javascript/description: text$markdown.md | 1 - .../javascript/text$javascript -> mmm$dom.js | 24 ---------- root/sandbox/lua/description: text$markdown.md | 1 - root/sandbox/lua/text$lua -> mmm$dom.lua | 10 ---- root/sandbox/text$lua -> fn -> mmm$dom.lua | 18 ------- 15 files changed, 43 insertions(+), 102 deletions(-) delete mode 100644 root/sandbox/description: text$markdown.md delete mode 100644 root/sandbox/dynamic-children/a/text$lua -> table delete mode 100644 root/sandbox/dynamic-children/b/text$markdown.md delete mode 100644 root/sandbox/dynamic-children/c/text$javascript -> text$markdown.js delete mode 100644 root/sandbox/dynamic-children/description: text$markdown.md delete mode 100644 root/sandbox/dynamic-children/text$lua -> fn -> mmm$dom.lua delete mode 100644 root/sandbox/javascript/description: text$markdown.md delete mode 100644 root/sandbox/javascript/text$javascript -> mmm$dom.js delete mode 100644 root/sandbox/lua/description: text$markdown.md delete mode 100644 root/sandbox/lua/text$lua -> mmm$dom.lua delete mode 100644 root/sandbox/text$lua -> fn -> mmm$dom.lua diff --git a/Dockerfile b/Dockerfile index f95ac67..ef1246b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,4 +16,4 @@ WORKDIR /code RUN tup init && tup generate --config tup.docker.config build-static.sh && ./build-static.sh EXPOSE 8000 -ENTRYPOINT ["moon", "build/server.moon", "fs", "0.0.0.0", "8000", "^/sandbox/"] +ENTRYPOINT ["moon", "build/server.moon", "fs", "0.0.0.0", "8000"] diff --git a/build/server.moon b/build/server.moon index b219c58..152e4e5 100644 --- a/build/server.moon +++ b/build/server.moon @@ -8,7 +8,6 @@ add '?/init' add '?/init.server' require 'mmm' -require 'mmm.mmmfs' import dir_base, Key, Fileder from require 'mmm.mmmfs.fileder' import convert from require 'mmm.mmmfs.conversion' @@ -21,8 +20,6 @@ lfs = require 'lfs' server = require 'http.server' headers = require 'http.headers' -export UNSAFE - class Server new: (@store, opts={}) => opts = {k,v for k,v in pairs opts} @@ -31,18 +28,28 @@ class Server opts.onstream = @\stream opts.onerror = @\error - if opts.host == 'localhost' - UNSAFE = true + @server = server.listen opts - @editable_paths = opts.editable_paths + @flags = opts.flags - @server = server.listen opts + if @flags.rw == nil + @flags.rw = opts.host == 'localhost' or opts.host == '127.0.0.1' + + if @flags.unsafe == nil + @flags.unsafe = opts.host == 'localhost' or opts.host == '127.0.0.1' + + export UNSAFE + UNSAFE = @flags.unsafe + require 'mmm.mmmfs' listen: => assert @server\listen! _, ip, port = @server\localname! - print "[#{@@__name}]", "running at #{ip}:#{port}" + print "[#{@@__name}]", + "running at #{ip}:#{port}", + "[#{table.concat [flag for flag,on in pairs @flags when on], ', '}]" + assert @server\loop! handle_interactive: (fileder, facet) => @@ -88,9 +95,8 @@ class Server -- fileder not found 404, "fileder '#{path}' not found" - if method != 'GET' and method != 'HEAD' - if not @editable_paths or not path\match @editable_paths - return 403, 'editing not allowed' + if not @flags.rw and method != 'GET' and method != 'HEAD' + return 403, 'editing not allowed' switch method when 'GET', 'HEAD' @@ -164,13 +170,27 @@ class Server msg = "#{msg}: #{err}" if err -- usage: --- moon server.moon [STORE] [host] [port] [editable-paths] --- * STORE: see mmm/mmmfs/stores/init.moon:get_store --- * host: interface to bind to (default localhost, set to 0.0.0.0 for public hosting) --- * port: port to serve from, default 8000 --- * editable-paths: Lua pattern to match paths in which editing is allowed, default none -{ store, host, port, editable_paths } = arg +-- moon server.moon [FLAGS] [STORE] [host] [port] +-- * FLAGS - any of the following: +-- --[no-]rw - enable/disable POST?PUT/DELETE operations (default: on if local) +-- --[no-]unsafe - enable/disable server-side code execution when writable is on (default: on if local) +-- * STORE - see mmm/mmmfs/stores/init.moon:get_store +-- * host - interface to bind to (default localhost, set to 0.0.0.0 for public hosting) +-- * port - port to serve from, default 8000 + +flags = {} +arguments = for a in *arg + if flag = a\match '^%-%-no%-(.*)$' + flags[flag] = false + continue + elseif flag = a\match '^%-%-(.*)$' + flags[flag] = true + continue + else + a + +{ store, host, port } = arguments store = get_store store -server = Server store, :host, :editable_paths, port: port and tonumber port +server = Server store, :flags, :host, port: port and tonumber port server\listen! diff --git a/mmm/init.client.moon b/mmm/init.client.moon index be286d8..5fb3450 100644 --- a/mmm/init.client.moon +++ b/mmm/init.client.moon @@ -1,10 +1,11 @@ -export MODE, print, warn, relative, on_load +export MODE, UNSAFE, print, warn, relative, on_load export window, document window = js.global { :document, :console } = window MODE = 'CLIENT' +UNSAFE = true deep_tostring = (tbl, space='') -> return tbl if 'userdata' == type tbl diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index b63010b..2e5652e 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -1,6 +1,5 @@ require = relative ..., 1 import Key from require '.fileder' -import converts, editors from require '.plugins' import get_conversions, apply_conversions from require '.conversion' import ReactiveVar, get_or_create, text, elements, tohtml from require 'mmm.component' import pre, div, nav, span, button, a, code, option from elements @@ -29,7 +28,7 @@ casts = { transform: (href) => span a (code href), :href } } -casts = combine casts, converts, editors +get_casts = -> combine casts, PLUGINS.converts, PLUGINS.editors export BROWSER class Browser @@ -239,7 +238,7 @@ class Browser value, key = @get prop assert key, "couldn't @get #{prop}" - conversions = get_conversions 'mmm/dom', key.type, casts + conversions = get_conversions 'mmm/dom', key.type, get_casts assert conversions, "cannot cast '#{key.type}'" apply_conversions conversions, value, @, prop diff --git a/root/sandbox/description: text$markdown.md b/root/sandbox/description: text$markdown.md deleted file mode 100644 index 250bb4e..0000000 --- a/root/sandbox/description: text$markdown.md +++ /dev/null @@ -1,5 +0,0 @@ -Everything in this Fileder is world-editable on the internet. -It will be reset to its' default state whenever I push my repository. -Please behave. - -Here is a list of this fileders content: diff --git a/root/sandbox/dynamic-children/a/text$lua -> table b/root/sandbox/dynamic-children/a/text$lua -> table deleted file mode 100644 index e69de29..0000000 diff --git a/root/sandbox/dynamic-children/b/text$markdown.md b/root/sandbox/dynamic-children/b/text$markdown.md deleted file mode 100644 index e69de29..0000000 diff --git a/root/sandbox/dynamic-children/c/text$javascript -> text$markdown.js b/root/sandbox/dynamic-children/c/text$javascript -> text$markdown.js deleted file mode 100644 index e69de29..0000000 diff --git a/root/sandbox/dynamic-children/description: text$markdown.md b/root/sandbox/dynamic-children/description: text$markdown.md deleted file mode 100644 index 32216ce..0000000 --- a/root/sandbox/dynamic-children/description: text$markdown.md +++ /dev/null @@ -1 +0,0 @@ -dynamically embedding children fileders with Lua diff --git a/root/sandbox/dynamic-children/text$lua -> fn -> mmm$dom.lua b/root/sandbox/dynamic-children/text$lua -> fn -> mmm$dom.lua deleted file mode 100644 index a3a019b..0000000 --- a/root/sandbox/dynamic-children/text$lua -> fn -> mmm$dom.lua +++ /dev/null @@ -1,19 +0,0 @@ -local d = require 'mmm.dom' -local u = require('mmm.mmmfs.util')(d) - --- we need to return a function to get access to the current fileder --- (thats why there is the '-> fn ->' in the type) -return function(self) - local children = {} - for i, child in ipairs(self.children) do - table.insert(children, d.li { - 'child ' .. i .. ': ', - u.link_to(child), - }) - end - - return d.article { - d.h1 'The Children are:', - d.ul(children), - } -end diff --git a/root/sandbox/javascript/description: text$markdown.md b/root/sandbox/javascript/description: text$markdown.md deleted file mode 100644 index eb0ca7c..0000000 --- a/root/sandbox/javascript/description: text$markdown.md +++ /dev/null @@ -1 +0,0 @@ -an example of how to use JS to create (dynamic) DOM / mmmfs content diff --git a/root/sandbox/javascript/text$javascript -> mmm$dom.js b/root/sandbox/javascript/text$javascript -> mmm$dom.js deleted file mode 100644 index 58deb23..0000000 --- a/root/sandbox/javascript/text$javascript -> mmm$dom.js +++ /dev/null @@ -1,24 +0,0 @@ -// a little helper function for creating DOM elements -const e = (elem, children) => { - const node = document.createElement(elem); - - if (typeof children === 'string') - node.innerText = children; - else - children.forEach(child => node.appendChild(child)); - - return node; -}; - -/* creating the equivalent of the following HTML directly as DOM content: - * - *
- *

JavaScript

- *

...

- *
- */ - -return e('article', [ - e('h1', 'JavaScript'), - e('p', 'JavaScript is supported natively in the browser but is not currently pre-rendered on the server.'), -]); diff --git a/root/sandbox/lua/description: text$markdown.md b/root/sandbox/lua/description: text$markdown.md deleted file mode 100644 index 3071697..0000000 --- a/root/sandbox/lua/description: text$markdown.md +++ /dev/null @@ -1 +0,0 @@ -an example of how to use Lua to create (dynamic) DOM / mmmfs content diff --git a/root/sandbox/lua/text$lua -> mmm$dom.lua b/root/sandbox/lua/text$lua -> mmm$dom.lua deleted file mode 100644 index db420ce..0000000 --- a/root/sandbox/lua/text$lua -> mmm$dom.lua +++ /dev/null @@ -1,10 +0,0 @@ --- see /meta/mmm.dom for documentation -local d = require 'mmm.dom' - -local lua = d.a { 'Lua', href = 'https://www.lua.org/' } -local fengari = d.a { 'fengari.io', href = 'https://fengari.io/' } - -return d.article { - d.h1 'Lua', - d.p { lua, ' is fully supported using ', fengari, ' on the Client.' } -} diff --git a/root/sandbox/text$lua -> fn -> mmm$dom.lua b/root/sandbox/text$lua -> fn -> mmm$dom.lua deleted file mode 100644 index 18206bb..0000000 --- a/root/sandbox/text$lua -> fn -> mmm$dom.lua +++ /dev/null @@ -1,18 +0,0 @@ -local d = require 'mmm.dom' -local u = require('mmm.mmmfs.util')(d) - -return function(self) - local children = {} - for i, child in ipairs(self.children) do - table.insert( - children, - d.li(u.link_to(child), ': ', (child:get('description: mmm/dom'))) - ) - end - - return d.div({ - d.h3(u.link_to(self)), - self:gett('description: mmm/dom'), - d.ul(children), - }) -end -- cgit v1.2.3 From 4f5c88bd322614d9bb3a06d53eedbaa1d710495d Mon Sep 17 00:00:00 2001 From: s-ol Date: Wed, 30 Oct 2019 11:38:13 +0100 Subject: add ba_log 2019-10-29 --- .../mmmfs/ba_log/2019-10-29/text$markdown.md | 38 +++++++++++++++++++++ .../mmmfs/ba_log/2019-10-29/video/video$mp4.mp4 | Bin 0 -> 3944233 bytes 2 files changed, 38 insertions(+) create mode 100644 root/articles/mmmfs/ba_log/2019-10-29/text$markdown.md create mode 100644 root/articles/mmmfs/ba_log/2019-10-29/video/video$mp4.mp4 diff --git a/root/articles/mmmfs/ba_log/2019-10-29/text$markdown.md b/root/articles/mmmfs/ba_log/2019-10-29/text$markdown.md new file mode 100644 index 0000000..9656562 --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-10-29/text$markdown.md @@ -0,0 +1,38 @@ +Today i implemented updating/saving content in the server, and bridged the feature to the client. +In the inspector there is now a `save changes` button that (attempts to) save the content on +the server's filesystem \[[`4b8d9be`][4b8d9be]\]. + +demonstration of editing and persistantly saving facet + +Originally I wanted to create a `sandbox` fileder that was to be edited by any one online \[[`d9eafa2`][d9eafa2]\]. +I restricted editing to only fileders underneath `/sandbox`, but then upon publishing quickly realized +that this left open a major security vulnerability, since content can be evaluated on server or client: +if a client were to create a facet `exploit: text/lua -> text/plain` with the following content in the root: + +```lua +pass = io.open('/etc/passwd', 'r') +return pass:read("*all") +``` + +...and then request that facet as converted to `text/plain` (`GET /exploit: text/plain`), +then that Lua code would be executed on the server, and return the confidential `passwd` file on the server. +This basically meant handing anyone online full unconditionaly access to my server +(or at least the VM running the website, and potentially options to escalate from there). + +As a result I had to choose to either disable public editing, or disable server-side code execution. +Because server-side execution is a major feature of mmmfs, I settled for the following compromise \[[`1e3b0a1`][1e3b0a1]\]: + +- when developing and running locally, editing and code execution are both enabled in 'unsafe mode' +- on https://ba.s-ol.nu, editing is disabled but code execution is possible +- on https://sandbox.s-ol.nu, editing is enabled but code server-side code execution is disabled + +The Sandbox can now be found at the following address, at least until the thesis project is concluded: + +# [`sandbox.s-ol.nu`](https://sandbox.s-ol.nu) + +Currently it is only possible to edit existing facets, +but creation and deletion of facets and fileders should be implemented soon. + +[4b8d9be]: https://git.s-ol.nu/mmm/commit/4b8d9be10e4517114c0c216fa24aaaa310503d4a/ +[d9eafa2]: https://git.s-ol.nu/mmm/commit/d9eafa21ad1d6ad340b5744d69e9fc68ce2083cb/ +[1e3b0a1]: https://git.s-ol.nu/mmm/commit/1e3b0a12060dce916b686921c94520202c4cb130/ diff --git a/root/articles/mmmfs/ba_log/2019-10-29/video/video$mp4.mp4 b/root/articles/mmmfs/ba_log/2019-10-29/video/video$mp4.mp4 new file mode 100644 index 0000000..162d0fc Binary files /dev/null and b/root/articles/mmmfs/ba_log/2019-10-29/video/video$mp4.mp4 differ -- cgit v1.2.3 From 3c79e6904c2df4e542d43b9e1068c75384fb6a89 Mon Sep 17 00:00:00 2001 From: s-ol Date: Wed, 30 Oct 2019 11:51:43 +0100 Subject: fix embed in static rendered markdown --- mmm/mmmfs/util.moon | 7 ++++--- scss/_content.scss | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mmm/mmmfs/util.moon b/mmm/mmmfs/util.moon index eb5d025..0e57f93 100644 --- a/mmm/mmmfs/util.moon +++ b/mmm/mmmfs/util.moon @@ -10,7 +10,7 @@ tourl = (path) -> path .. '/' (elements) -> - import a, div, pre from elements + import a, div, span, pre from elements find_fileder = (fileder, origin) -> if 'string' == type fileder @@ -53,8 +53,9 @@ tourl = (path) -> ok, node = pcall fileder.gett, fileder, name, 'mmm/dom' if not ok - return div "couldn't embed #{fileder} #{name}", + return span "couldn't embed #{fileder} #{name}", (pre node), + class: 'embed' style: { background: 'var(--gray-fail)', padding: '1em', @@ -64,7 +65,7 @@ tourl = (path) -> klass ..= ' desc' if opts.desc klass ..= ' inline' if opts.inline - node = div { + node = span { class: klass node if opts.desc diff --git a/scss/_content.scss b/scss/_content.scss index 6993fef..51994a3 100644 --- a/scss/_content.scss +++ b/scss/_content.scss @@ -27,6 +27,7 @@ } .embed { + display: block; width: inherit; height: inherit; max-width: inherit; -- cgit v1.2.3 From 2525b6c2f45397c80c5cb46dc0f9e1d68a615bea Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 31 Oct 2019 14:43:38 +0100 Subject: small fixes: * --unsafe by default if not --rw * fix inspector --- build/server.moon | 4 ++-- mmm/mmmfs/browser.moon | 2 +- mmm/mmmfs/init.moon | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/build/server.moon b/build/server.moon index 152e4e5..fb6dca4 100644 --- a/build/server.moon +++ b/build/server.moon @@ -36,7 +36,7 @@ class Server @flags.rw = opts.host == 'localhost' or opts.host == '127.0.0.1' if @flags.unsafe == nil - @flags.unsafe = opts.host == 'localhost' or opts.host == '127.0.0.1' + @flags.unsafe = not @flags.rw or opts.host == 'localhost' or opts.host == '127.0.0.1' export UNSAFE UNSAFE = @flags.unsafe @@ -173,7 +173,7 @@ class Server -- moon server.moon [FLAGS] [STORE] [host] [port] -- * FLAGS - any of the following: -- --[no-]rw - enable/disable POST?PUT/DELETE operations (default: on if local) --- --[no-]unsafe - enable/disable server-side code execution when writable is on (default: on if local) +-- --[no-]unsafe - enable/disable server-side code execution when writable is on (default: on if local or --no-rw) -- * STORE - see mmm/mmmfs/stores/init.moon:get_store -- * host - interface to bind to (default localhost, set to 0.0.0.0 for public hosting) -- * port - port to serve from, default 8000 diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index 2e5652e..8d95ac3 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -238,7 +238,7 @@ class Browser value, key = @get prop assert key, "couldn't @get #{prop}" - conversions = get_conversions 'mmm/dom', key.type, get_casts + conversions = get_conversions 'mmm/dom', key.type, get_casts! assert conversions, "cannot cast '#{key.type}'" apply_conversions conversions, value, @, prop diff --git a/mmm/mmmfs/init.moon b/mmm/mmmfs/init.moon index fc89d7f..b807c1c 100644 --- a/mmm/mmmfs/init.moon +++ b/mmm/mmmfs/init.moon @@ -2,3 +2,4 @@ require = relative ..., 0 export ^ PLUGINS = require '.plugins' +print "PLUGINS = ", PLUGINS -- cgit v1.2.3 From dc08e262cd53a48480a88235aa58500f0638ad79 Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 31 Oct 2019 17:14:07 +0100 Subject: allow adding and removing of facets --- mmm/mmmfs/browser.moon | 39 ++++++++++++++++++++++++++------------- mmm/mmmfs/fileder.moon | 23 +++++++++++++++-------- mmm/mmmfs/init.moon | 1 - mmm/mmmfs/plugins/init.moon | 2 +- scss/_browser.scss | 4 ++++ 5 files changed, 46 insertions(+), 23 deletions(-) diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index 8d95ac3..7be702f 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -43,13 +43,13 @@ class Browser -- active fileder -- (re)set every time @path changes - @active = @path\map @root\walk + @fileder = @path\map @root\walk -- currently active facet - -- (re)set to default when @active changes + -- (re)set to default when @fileder changes @facet = ReactiveVar Key facet, 'mmm/dom' if MODE == 'CLIENT' - @active\subscribe (fileder) -> + @fileder\subscribe (fileder) -> return unless fileder last = @facet and @facet\get! @facet\set Key if last then last.type else 'mmm/dom' @@ -119,7 +119,7 @@ class Browser \append path_segment name, href \append span 'view facet:', style: { 'margin-right': '0' } - \append @active\map (fileder) -> + \append @fileder\map (fileder) -> onchange = (_, e) -> { :type } = @facet\get! @facet\set Key name: e.target.value, :type @@ -178,7 +178,7 @@ class Browser warn "ERROR rendering content: #{msg}" div! - active = @active\get! + active = @fileder\get! return disp_error "fileder not found!" unless active return disp_error "facet not found!" unless prop @@ -201,7 +201,7 @@ class Browser -- active facet in inspect tab -- (re)set to match when @facet changes @inspect_prop = @facet\map (prop) -> - active = @active\get! + active = @fileder\get! key = active and active\find prop key = key.original if key and key.original key @@ -213,21 +213,34 @@ class Browser span 'inspector' @inspect_prop\map (current) -> current = current and current\tostring! - fileder = @active\get! + fileder = @fileder\get! onchange = (_, e) -> - return if e.target.value == '' - { :name } = @facet\get! - @inspect_prop\set Key e.target.value + facet = e.target.value + return if facet == '' + @inspect_prop\set Key facet with elements.select :onchange \append option '(none)', value: '', disabled: true, selected: not value if fileder for value in pairs fileder.facet_keys \append option value, :value, selected: value == current - @inspect\map (enabled) -> - if enabled - button 'close', onclick: (_, e) -> @inspect\set false + + button 'rm', class: 'tight', onclick: (_, e) -> + if window\confirm "continuing will permanently remove the facet '#{@inspect_prop\get!}'." + fileder = @fileder\get! + fileder\set @inspect_prop\get!, nil + @fileder\set fileder -- trigger re-selection of active facet & inspector + + button 'add', class: 'tight', onclick: (_, e) -> + facet = window\prompt "please enter the facet string ('name: type' or 'type'):", 'text/markdown' + return if not facet or facet == '' or facet == js.null + fileder = @fileder\get! + fileder\set facet, '' + @inspect_prop\set Key facet + @refresh! + + button 'close', onclick: (_, e) -> @inspect\set false } \append with div class: @inspect_err\map (e) -> if e then 'error-wrap' else 'error-wrap empty' \append span "an error occured while rendering this view:" diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index 9918adc..dec0350 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -135,13 +135,18 @@ class Fileder __newindex: (t, k, v) -> -- get canonical Key instance - k = @facet_keys[k] - return unless k + key = @facet_keys[k] - rawset t, k, v + -- new creating, also create canonical Key + if not key + key = Key k + @facet_keys[key] = key + rawset t, key, v + + -- when deleting, also delete canonical Key if not v - @facet_keys[k] = nil + @facet_keys[key] = nil } -- this fails with JS objects from JSON.parse @@ -243,15 +248,15 @@ class Fileder -- find facet and type according to criteria, nil if no value or conversion path -- * ... - arguments like Key - find: (...) => - want = Key ... + find: (key, key2, ...) => + want = Key key, key2 -- filter facets by name matching = [ key for str, key in pairs @facet_keys when key.name == want.name ] return unless #matching > 0 -- get shortest conversion path - shortest_path, start = get_conversions want.type, [ key.type for key in *matching ] + shortest_path, start = get_conversions want.type, [ key.type for key in *matching ], ... if start for key in *matching @@ -292,7 +297,9 @@ class Fileder key = Key key value = key2 - if @facet_keys[key] + if value == nil + @store\remove_facet @path, key.name, key.type + elseif @facet_keys[key] @store\update_facet @path, key.name, key.type, value else @store\create_facet @path, key.name, key.type, value diff --git a/mmm/mmmfs/init.moon b/mmm/mmmfs/init.moon index b807c1c..fc89d7f 100644 --- a/mmm/mmmfs/init.moon +++ b/mmm/mmmfs/init.moon @@ -2,4 +2,3 @@ require = relative ..., 0 export ^ PLUGINS = require '.plugins' -print "PLUGINS = ", PLUGINS diff --git a/mmm/mmmfs/plugins/init.moon b/mmm/mmmfs/plugins/init.moon index 583fbb4..5afd7be 100644 --- a/mmm/mmmfs/plugins/init.moon +++ b/mmm/mmmfs/plugins/init.moon @@ -56,7 +56,7 @@ converts = { { inp: 'text/html%+frag', out: 'mmm/dom', - cost: 1 + cost: 0.1 transform: if MODE == 'SERVER' (html, fileder) => html = html\gsub '(.-)', (attrs, text) -> diff --git a/scss/_browser.scss b/scss/_browser.scss index 1c5b5b2..47be262 100644 --- a/scss/_browser.scss +++ b/scss/_browser.scss @@ -72,6 +72,10 @@ > .inspect-btn { @include media-small() { display: none; } } + + .tight { + margin-left: 0; + } } .error-wrap { -- cgit v1.2.3 From 938a524f623ba08430085fe6c33fcc77f94b3127 Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 31 Oct 2019 17:15:23 +0100 Subject: add DEBUG pseudo-type for debugging conversion --- build/server.moon | 10 ++++++++- mmm/mmmfs/conversion.moon | 55 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/build/server.moon b/build/server.moon index fb6dca4..99076bf 100644 --- a/build/server.moon +++ b/build/server.moon @@ -10,7 +10,7 @@ add '?/init.server' require 'mmm' import dir_base, Key, Fileder from require 'mmm.mmmfs.fileder' -import convert from require 'mmm.mmmfs.conversion' +import convert, MermaidDebugger from require 'mmm.mmmfs.conversion' import get_store from require 'mmm.mmmfs.stores' import render from require 'mmm.mmmfs.layout' import Browser from require 'mmm.mmmfs.browser' @@ -88,6 +88,11 @@ class Server end) " + handle_debug: (fileder, facet) => + debugger = MermaidDebugger! + fileder\find facet, nil, nil, nil, debugger + convert 'text/mermaid-graph', 'text/html', debugger\render!, fileder, facet.name + handle: (method, path, facet, value) => fileder = Fileder @store, path @@ -111,6 +116,9 @@ class Server else if facet.type == 'text/html+interactive' @handle_interactive fileder, facet + else if base = facet.type\match '^DEBUG %-> (.*)' + facet.type = base + @handle_debug fileder, facet else if not fileder\has_facet facet.name 404, "facet '#{facet.name}' not found in fileder '#{path}'" else diff --git a/mmm/mmmfs/conversion.moon b/mmm/mmmfs/conversion.moon index c0505a8..863b6af 100644 --- a/mmm/mmmfs/conversion.moon +++ b/mmm/mmmfs/conversion.moon @@ -7,12 +7,51 @@ escape_inp = (inp) -> "^#{inp\gsub '([-/])', '%%%1'}$" local print_conversions +class MermaidDebugger + new: => + nextid = 0 + @type_id = setmetatable {}, __index: (t, k) -> + nextid += 1 + with val = "type-#{nextid}" + t[k] = val + + @cost = {} + @buf = "graph TD\n" + + append: (line) => + @buf ..= " #{line}\n" + + found_type: (type) => + type_id = @type_id[type] + + type_cost: (type, cost) => + if old_cost = @cost[type] + cost = math.min old_cost, cost + @cost[type] = cost + + type_class: (type, klass) => + @append "class #{@type_id[type]} #{klass}" + + found_link: (frm, to, cost) => + @append "#{@type_id[frm]} -- cost: #{cost} --> #{@type_id[to]}" + + render: => + for type, id in pairs @type_id + cost = @cost[type] or -1 + @append "#{id}[\"#{type} [#{cost}]\"]" + + @append "classDef have fill:#ada" + @append "classDef want fill:#add" + + @buf + -- attempt to find a conversion path from 'have' to 'want' -- * have - start type string or list of type strings -- * want - stop type pattern -- * limit - limit conversion amount +-- * debug - a table with debug hooks -- returns a list of conversion steps -get_conversions = (want, have, converts=PLUGINS and PLUGINS.converts, limit=5) -> +get_conversions = (want, have, converts=PLUGINS and PLUGINS.converts, limit=5, debug) -> assert have, 'need starting type(s)' assert converts, 'need to pass list of converts' @@ -30,6 +69,11 @@ get_conversions = (want, have, converts=PLUGINS and PLUGINS.converts, limit=5) - return {}, start if want\match start queue\add { :start, rest: start, conversions: {} }, 0, start + if debug + debug\found_type start + debug\type_cost start, 0 + debug\type_class start, 'have' + best = Queue! while true @@ -53,12 +97,17 @@ get_conversions = (want, have, converts=PLUGINS and PLUGINS.converts, limit=5) - conversions: { { :convert, from: rest, to: result }, table.unpack conversions } } + if debug + debug\found_type result + debug\type_cost result, next_entry.cost + debug\found_link rest, result, convert.cost + if result\match want + debug\type_class result, 'want' if debug best\add next_entry, next_entry.cost else queue\add next_entry, next_entry.cost, result - if solution = best\pop! -- print "BEST: (#{solution.cost})" -- print_conversions solution.conversions @@ -106,6 +155,8 @@ convert = (have, want, value, ...) -> apply_conversions conversions, value, ... { + :MermaidDebugger + :get_conversions :apply_conversions :convert -- cgit v1.2.3 From ff9ee8e99cd5f5c420ba0501c335ac18f1b10769 Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 31 Oct 2019 18:26:31 +0100 Subject: browsing, adding, removing fileders in inspector --- build/server.moon | 39 ++++++++++++++++++++++++-------------- mmm/mmmfs/browser.moon | 48 ++++++++++++++++++++++++++++++++++++++++++----- mmm/mmmfs/fileder.moon | 12 ++++++++++++ mmm/mmmfs/stores/fs.moon | 2 +- mmm/mmmfs/stores/web.moon | 5 +++-- scss/_browser.scss | 8 ++++++++ 6 files changed, 92 insertions(+), 22 deletions(-) diff --git a/build/server.moon b/build/server.moon index 99076bf..395b903 100644 --- a/build/server.moon +++ b/build/server.moon @@ -94,17 +94,16 @@ class Server convert 'text/mermaid-graph', 'text/html', debugger\render!, fileder, facet.name handle: (method, path, facet, value) => - fileder = Fileder @store, path - - if not fileder - -- fileder not found - 404, "fileder '#{path}' not found" - if not @flags.rw and method != 'GET' and method != 'HEAD' return 403, 'editing not allowed' switch method when 'GET', 'HEAD' + fileder = Fileder @store, path + if not fileder + -- fileder not found + return 404, "fileder '#{path}' not found" + val = switch facet.name when '?index', '?tree' -- serve fileder index @@ -129,13 +128,22 @@ class Server else 406, "cant convert facet '#{facet.name}' to '#{facet.type}'" when 'POST' - @store\create_facet path, facet.name, facet.type, value - 200, 'ok' + if facet + @store\create_facet path, facet.name, facet.type, value + 200, 'ok' + else + 200, @store\create_fileder dir_base path when 'PUT' - @store\update_facet path, facet.name, facet.type, value - 200, 'ok' + if facet + @store\update_facet path, facet.name, facet.type, value + 200, 'ok' + else + 501, "not implemented" when 'DELETE' - @store\remove_facet path, facet.name, facet.type + if facet + @store\remove_facet path, facet.name, facet.type + else + @store\remove_fileder path 200, 'ok' else 501, "not implemented" @@ -151,9 +159,12 @@ class Server path_facet or= path path, facet = path_facet\match '(.*)/([^/]*)' - type or= 'text/html+interactive' - type = type\match '%s*(.*)' - facet = Key facet, type + facet = if facet == '' and method ~= 'GET' and method ~= 'HEAD' + nil + else + type or= 'text/html+interactive' + type = type\match '%s*(.*)' + Key facet, type value = stream\get_body_as_string! ok, status, body = xpcall @.handle, err_and_trace, @, method, path, facet, value diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index 7be702f..6020eb7 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -2,7 +2,8 @@ require = relative ..., 1 import Key from require '.fileder' import get_conversions, apply_conversions from require '.conversion' import ReactiveVar, get_or_create, text, elements, tohtml from require 'mmm.component' -import pre, div, nav, span, button, a, code, option from elements +import pre, div, nav, span, button, a, code, select, option from elements +import link_to from (require '.util') elements import languages from require 'mmm.highlighting' keep = (var) -> @@ -166,7 +167,10 @@ class Browser -- rerender main content refresh: (facet=@facet\get!) => - @content\set @get_content facet + if facet == true -- deep refresh + @fileder\transform (i) -> i + else + @content\set @get_content facet -- render #browser-content get_content: (prop, err=@error, convert=default_convert) => @@ -220,8 +224,7 @@ class Browser return if facet == '' @inspect_prop\set Key facet - with elements.select :onchange - \append option '(none)', value: '', disabled: true, selected: not value + with select :onchange \append option '(none)', value: '', disabled: true, selected: not value if fileder for value in pairs fileder.facet_keys \append option value, :value, selected: value == current @@ -230,7 +233,7 @@ class Browser if window\confirm "continuing will permanently remove the facet '#{@inspect_prop\get!}'." fileder = @fileder\get! fileder\set @inspect_prop\get!, nil - @fileder\set fileder -- trigger re-selection of active facet & inspector + @refresh true button 'add', class: 'tight', onclick: (_, e) -> facet = window\prompt "please enter the facet string ('name: type' or 'type'):", 'text/markdown' @@ -255,6 +258,41 @@ class Browser assert conversions, "cannot cast '#{key.type}'" apply_conversions conversions, value, @, prop + \append nav { + span 'children' + button 'add', onclick: (_, e) -> + name = window\prompt "please enter the name of the child fileder:", 'unnamed_fileder' + return if not name or name == '' or name == js.null + child = @fileder\get!\add_child name + @refresh true + } + \append @fileder\map (fileder) -> + with div class: 'children' + num = #fileder.children + for i, child in ipairs fileder.children + name = child\gett 'name: alpha' + \append div { + style: + display: 'flex' + 'justify-content': 'space-between' + + span '- ', (link_to child, code name), style: flex: 1 + + button '↑', disabled: i == 1, onclick: (_, e) -> + fileder\reorder_child name, i - 1 + @refresh true + + button '↓', disabled: i == num, onclick: (_, e) -> + fileder\reorder_child name, i + 1 + @refresh true + + button 'rm', onclick: (_, e) -> + if window\confirm "continuing will permanently remove all content in '#{child.path}'." + fileder\remove_child i + @refresh true + } + + default_convert = (key) => @get key.name, 'mmm/dom' navigate: (new) => diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index dec0350..b42c6dd 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -306,6 +306,18 @@ class Fileder @facets[key] = value + -- add a child fileder with given name + add_child: (name) => + new_path = @store\create_fileder @path, name + with new_child = Fileder @store, new_path + table.insert @children, new_child + + -- remove a child with given index + remove_child: (i) => + removed = table.remove @children, i + assert removed, "no such child fileder" + @store\remove_fileder removed.path + __tostring: => "Fileder:#{@path}" { diff --git a/mmm/mmmfs/stores/fs.moon b/mmm/mmmfs/stores/fs.moon index 1e09d1d..d4d5bd4 100644 --- a/mmm/mmmfs/stores/fs.moon +++ b/mmm/mmmfs/stores/fs.moon @@ -50,8 +50,8 @@ class FSStore extends Store coroutine.yield path create_fileder: (parent, name) => - @log "creating fileder #{path}" path = "#{parent}/#{name}" + @log "creating fileder #{path}" assert lfs.mkdir @root .. path path diff --git a/mmm/mmmfs/stores/web.moon b/mmm/mmmfs/stores/web.moon index ed3f6d7..b498d79 100644 --- a/mmm/mmmfs/stores/web.moon +++ b/mmm/mmmfs/stores/web.moon @@ -61,12 +61,13 @@ class WebStore extends Store coroutine.yield child.path create_fileder: (parent, name) => + path = "#{parent}/#{name}" @log "creating fileder #{path}" - error "not implemented" + req 'POST', "#{@host .. path}/" remove_fileder: (path) => @log "removing fileder #{path}" - error "not implemented" + req 'DELETE', "#{@host .. path}/" rename_fileder: (path, next_name) => @log "renaming fileder #{path} -> '#{next_name}'" diff --git a/scss/_browser.scss b/scss/_browser.scss index 47be262..f39e1df 100644 --- a/scss/_browser.scss +++ b/scss/_browser.scss @@ -42,6 +42,14 @@ flex: 1; } } + + .children { + margin: 0; + padding: 1em; + + align-self: stretch; + background: $gray-darker; + } } nav { -- cgit v1.2.3 From 053e607a49989b2d4491c20ff14c839b7161d713 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 1 Nov 2019 13:47:09 +0100 Subject: add proper order handling, fsck for stores.fs --- build/fsck.moon | 37 ++++++++++++++++++++++ mmm/mmmfs/stores/fs.moon | 78 ++++++++++++++++++++++++++++++++++++++-------- mmm/mmmfs/stores/init.moon | 3 +- 3 files changed, 104 insertions(+), 14 deletions(-) create mode 100644 build/fsck.moon diff --git a/build/fsck.moon b/build/fsck.moon new file mode 100644 index 0000000..df882a9 --- /dev/null +++ b/build/fsck.moon @@ -0,0 +1,37 @@ +add = (tmpl) -> + package.path ..= ";#{tmpl}.lua" + package.moonpath ..= ";#{tmpl}.moon" + +add '?' +add '?.server' +add '?/init' +add '?/init.server' + +require 'mmm' + +import get_store from require 'mmm.mmmfs.stores' + +-- usage: +-- moon server.moon [FLAGS] [STORE] [host] [port] +-- * FLAGS - any of the following: +-- --[no-]rw - enable/disable POST?PUT/DELETE operations (default: on if local) +-- --[no-]unsafe - enable/disable server-side code execution when writable is on (default: on if local or --no-rw) +-- * STORE - see mmm/mmmfs/stores/init.moon:get_store +-- * host - interface to bind to (default localhost, set to 0.0.0.0 for public hosting) +-- * port - port to serve from, default 8000 + +flags = {} +arguments = for a in *arg + if flag = a\match '^%-%-no%-(.*)$' + flags[flag] = false + continue + elseif flag = a\match '^%-%-(.*)$' + flags[flag] = true + continue + else + a + +{ store, host, port } = arguments + +store = get_store store, verbose: true +store\fsck! diff --git a/mmm/mmmfs/stores/fs.moon b/mmm/mmmfs/stores/fs.moon index d4d5bd4..edcca3b 100644 --- a/mmm/mmmfs/stores/fs.moon +++ b/mmm/mmmfs/stores/fs.moon @@ -21,38 +21,63 @@ class FSStore extends Store @log "opening '#{opts.root}'..." -- fileders - list_fileders_in: (path='') => + get_order: (path, forgiving=false) => entries = {} - for entry_name in lfs.dir @root .. path - continue if '.' == entry_name\sub 1, 1 - entry_path = @root .. "#{path}/#{entry_name}" + for name in lfs.dir @root .. path + continue if '.' == name\sub 1, 1 + entry_path = @root .. "#{path}/#{name}" if 'directory' ~= lfs.attributes entry_path, 'mode' continue - entries[entry_name] = "#{path}/#{entry_name}" + entries[name] = :name, path: "#{path}/#{name}" sorted = {} - order_file = @root .. "#{path}/$order" if 'file' == lfs.attributes order_file, 'mode' for line in io.lines order_file - path = assert entries[line], "entry in $order but not on disk: #{line}" - table.insert sorted, path + entry = entries[line] + if not entry + if forgiving + @log "removed stale entry '#{line}' from #{path}/$order" + continue + error "entry in $order but not on disk: #{line}" + + table.insert sorted, entry sorted[line] = true - entries = [path for entry, path in pairs entries when not sorted[entry]] - table.sort entries - for path in *entries - table.insert sorted, path + unsorted = [entry for name, entry in pairs entries when not sorted[entry.name]] + if forgiving + for entry in *unsorted + @log "adding new entry '#{entry.name}' in #{path}/$order" + table.insert sorted, entry + else + assert #unsorted == 0, unsorted[1] and "entry on disk but not in $order: #{unsorted[1].path}" + + sorted + + write_order: (path, order=@get_order path, true) => + order_file = @root .. "#{path}/$order" + if #order == 0 + os.remove order_file + return + + file = assert io.open order_file, 'w' + for { :name } in *order + file\write "#{name}\n" + file\close! + + list_fileders_in: (path='') => + sorted = @get_order path coroutine.wrap -> - for path in *sorted + for { :path } in *sorted coroutine.yield path create_fileder: (parent, name) => path = "#{parent}/#{name}" @log "creating fileder #{path}" assert lfs.mkdir @root .. path + @write_order parent path remove_fileder: (path) => @@ -73,6 +98,9 @@ class FSStore extends Store rmdir @root .. path + parent = dir_base path + @write_order parent + rename_fileder: (path, next_name) => @log "renaming fileder #{path} -> '#{next_name}'" parent, name = dir_base path @@ -83,6 +111,22 @@ class FSStore extends Store parent, name = dir_base path assert os.rename @root .. path, @root .. "#{next_parent}/#{name}" + -- swap two childrens' order + swap_fileders: (parent, name_a, name_b) => + @log "swapping #{name_a} and #{name_b} in #{parent}" + order = @get_order parent + local a, b + for i, entry in ipairs order + a = i if entry.name == name_a + b = i if entry.name == name_b + break if a and b + + assert a, "couldn't find #{parent}/#{name_a} in $order" + assert b, "couldn't find #{parent}/#{name_b} in $order" + + order[a], order[b] = order[b], order[a] + @write_order parent, order + -- facets list_facets: (path) => coroutine.wrap -> @@ -161,6 +205,14 @@ class FSStore extends Store file\write blob file\close! + -- fsck + fsck: (path='') => + order = @get_order path, true + @write_order path, order + + for { :path } in *order + @fsck path + { :FSStore } diff --git a/mmm/mmmfs/stores/init.moon b/mmm/mmmfs/stores/init.moon index 905188f..3d8480f 100644 --- a/mmm/mmmfs/stores/init.moon +++ b/mmm/mmmfs/stores/init.moon @@ -42,13 +42,14 @@ class Store @remove_facet path, name, type update_facet: => error "not implemented" close: => + fsck: => log: (...) => print "[#{@@__name}]", ... -- instantiate a store from a CLI arg -- e.g.: sql, fs:/path/to/root, sql:MEMORY, sql:db.sqlite3 -get_store = (args='sql', opts={verbose: true}) -> +get_store = (args='sql', opts={}) -> type, arg = args\match '(%w+):(.*)' type = args unless type -- cgit v1.2.3 From ce998c8ca5b6364314b65cd8bf3d698ace03ced7 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 1 Nov 2019 13:47:23 +0100 Subject: fsck root dir --- root/$order | 1 + root/articles/$order | 3 +++ root/articles/mmmfs/ba_log/$order | 11 +++++++++++ root/articles/mmmfs/ba_log/2019-10-27/$order | 1 + root/articles/mmmfs/ba_log/2019-10-29/$order | 1 + root/articles/mmmfs/examples/$order | 5 +++++ root/articles/mmmfs/examples/gallery/$order | 2 ++ root/articles/mmmfs/examples/language_support/$order | 3 +++ root/articles/mmmfs/mmmfs/$order | 3 +++ root/articles/xy-workshop/$order | 10 ++++++++++ root/articles/xy-workshop/01c/$order | 1 + root/articles/xy-workshop/08/$order | 1 + root/blog/$order | 11 +++++++++++ root/blog/aspect_ratios/$order | 1 + root/blog/automating_my_rice/$order | 15 +++++++++++++++ root/blog/clocks_triggers_gates/$order | 6 ++++++ root/blog/love_lua_photoshop_and_games/$order | 4 ++++ root/blog/ludum_dare_33_postmortem/$order | 2 ++ root/blog/stencils_101/$order | 7 +++++++ root/blog/stretching_gates/$order | 5 +++++ root/blog/video_synth_research/$order | 8 ++++++++ root/experiments/$order | 5 +++++ root/experiments/parallax_panels/$order | 2 ++ root/experiments/parallax_panels/viewer/$order | 1 + root/games/$order | 12 ++++++++++++ root/games/IYNX/$order | 6 ++++++ root/games/IYNX/pictures/$order | 6 ++++++ root/games/plonat_atek/$order | 3 +++ root/games/plonat_atek/pictures/$order | 3 +++ root/games/text$moonscript -> fn -> mmm$dom.moon | 2 +- root/projects/$order | 9 +++++++++ root/projects/VJmidiKit/$order | 11 +++++++++++ root/projects/btrktrl/$order | 13 +++++++++++++ root/projects/demoloops/$order | 16 ++++++++++++++++ root/projects/demoloops/squaregrid/$order | 3 +++ root/projects/iii-telefoni/$order | 2 ++ root/static/$order | 4 ++++ 37 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 root/articles/$order create mode 100644 root/articles/mmmfs/ba_log/$order create mode 100644 root/articles/mmmfs/ba_log/2019-10-27/$order create mode 100644 root/articles/mmmfs/ba_log/2019-10-29/$order create mode 100644 root/articles/mmmfs/examples/$order create mode 100644 root/articles/mmmfs/examples/gallery/$order create mode 100644 root/articles/mmmfs/examples/language_support/$order create mode 100644 root/articles/mmmfs/mmmfs/$order create mode 100644 root/articles/xy-workshop/$order create mode 100644 root/articles/xy-workshop/01c/$order create mode 100644 root/articles/xy-workshop/08/$order create mode 100644 root/blog/$order create mode 100644 root/blog/aspect_ratios/$order create mode 100644 root/blog/automating_my_rice/$order create mode 100644 root/blog/clocks_triggers_gates/$order create mode 100644 root/blog/love_lua_photoshop_and_games/$order create mode 100644 root/blog/ludum_dare_33_postmortem/$order create mode 100644 root/blog/stencils_101/$order create mode 100644 root/blog/stretching_gates/$order create mode 100644 root/blog/video_synth_research/$order create mode 100644 root/experiments/$order create mode 100644 root/experiments/parallax_panels/$order create mode 100644 root/experiments/parallax_panels/viewer/$order create mode 100644 root/games/$order create mode 100644 root/games/IYNX/$order create mode 100644 root/games/IYNX/pictures/$order create mode 100644 root/games/plonat_atek/$order create mode 100644 root/games/plonat_atek/pictures/$order create mode 100644 root/projects/$order create mode 100644 root/projects/VJmidiKit/$order create mode 100644 root/projects/btrktrl/$order create mode 100644 root/projects/demoloops/$order create mode 100644 root/projects/demoloops/squaregrid/$order create mode 100644 root/projects/iii-telefoni/$order create mode 100644 root/static/$order diff --git a/root/$order b/root/$order index f4a59b2..3990658 100644 --- a/root/$order +++ b/root/$order @@ -5,3 +5,4 @@ games projects experiments meta +static diff --git a/root/articles/$order b/root/articles/$order new file mode 100644 index 0000000..66aad40 --- /dev/null +++ b/root/articles/$order @@ -0,0 +1,3 @@ +mmmfs +xy-workshop +realities diff --git a/root/articles/mmmfs/ba_log/$order b/root/articles/mmmfs/ba_log/$order new file mode 100644 index 0000000..600a4d9 --- /dev/null +++ b/root/articles/mmmfs/ba_log/$order @@ -0,0 +1,11 @@ +2019-10-07 +2019-10-08 +2019-10-09 +2019-10-10 +2019-10-11 +2019-10-14 +2019-10-15 +2019-10-24 +2019-10-26 +2019-10-27 +2019-10-29 diff --git a/root/articles/mmmfs/ba_log/2019-10-27/$order b/root/articles/mmmfs/ba_log/2019-10-27/$order new file mode 100644 index 0000000..2b68b52 --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-10-27/$order @@ -0,0 +1 @@ +video diff --git a/root/articles/mmmfs/ba_log/2019-10-29/$order b/root/articles/mmmfs/ba_log/2019-10-29/$order new file mode 100644 index 0000000..2b68b52 --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-10-29/$order @@ -0,0 +1 @@ +video diff --git a/root/articles/mmmfs/examples/$order b/root/articles/mmmfs/examples/$order new file mode 100644 index 0000000..7428a7e --- /dev/null +++ b/root/articles/mmmfs/examples/$order @@ -0,0 +1,5 @@ +language_support +image +markdown +empty +gallery diff --git a/root/articles/mmmfs/examples/gallery/$order b/root/articles/mmmfs/examples/gallery/$order new file mode 100644 index 0000000..9d438bd --- /dev/null +++ b/root/articles/mmmfs/examples/gallery/$order @@ -0,0 +1,2 @@ +link_to_image +actual_image diff --git a/root/articles/mmmfs/examples/language_support/$order b/root/articles/mmmfs/examples/language_support/$order new file mode 100644 index 0000000..3cc0e47 --- /dev/null +++ b/root/articles/mmmfs/examples/language_support/$order @@ -0,0 +1,3 @@ +javascript +moonscript +lua diff --git a/root/articles/mmmfs/mmmfs/$order b/root/articles/mmmfs/mmmfs/$order new file mode 100644 index 0000000..5a5d5ab --- /dev/null +++ b/root/articles/mmmfs/mmmfs/$order @@ -0,0 +1,3 @@ +type_coercion_graph +tree_mmmfs +tree_mainstream diff --git a/root/articles/xy-workshop/$order b/root/articles/xy-workshop/$order new file mode 100644 index 0000000..4600622 --- /dev/null +++ b/root/articles/xy-workshop/$order @@ -0,0 +1,10 @@ +01 +02 +03 +05 +04 +07 +01b +06 +08 +01c diff --git a/root/articles/xy-workshop/01c/$order b/root/articles/xy-workshop/01c/$order new file mode 100644 index 0000000..2b68b52 --- /dev/null +++ b/root/articles/xy-workshop/01c/$order @@ -0,0 +1 @@ +video diff --git a/root/articles/xy-workshop/08/$order b/root/articles/xy-workshop/08/$order new file mode 100644 index 0000000..773b222 --- /dev/null +++ b/root/articles/xy-workshop/08/$order @@ -0,0 +1 @@ +image diff --git a/root/blog/$order b/root/blog/$order new file mode 100644 index 0000000..f0592d3 --- /dev/null +++ b/root/blog/$order @@ -0,0 +1,11 @@ +humane_filesystems +ludum_dare_33_postmortem +video_synth_research +love_lua_photoshop_and_games +clocks_triggers_gates +stretching_gates +stencils_101 +aspect_ratios +automating_my_rice +challenging_myself +self-hosted_virtual_home diff --git a/root/blog/aspect_ratios/$order b/root/blog/aspect_ratios/$order new file mode 100644 index 0000000..09e38bd --- /dev/null +++ b/root/blog/aspect_ratios/$order @@ -0,0 +1 @@ +interactive diff --git a/root/blog/automating_my_rice/$order b/root/blog/automating_my_rice/$order new file mode 100644 index 0000000..17ec504 --- /dev/null +++ b/root/blog/automating_my_rice/$order @@ -0,0 +1,15 @@ +sexy +dark +bwcube +tattooed +polysun +hotline +sidewalk +akira +laying +touching +twostripe +trippy +polar +cavetree +psych diff --git a/root/blog/clocks_triggers_gates/$order b/root/blog/clocks_triggers_gates/$order new file mode 100644 index 0000000..f4ac304 --- /dev/null +++ b/root/blog/clocks_triggers_gates/$order @@ -0,0 +1,6 @@ +tyktok_test +tyktok_leds +tyktok_tired +metronome +tyktok_tomcat +threshold diff --git a/root/blog/love_lua_photoshop_and_games/$order b/root/blog/love_lua_photoshop_and_games/$order new file mode 100644 index 0000000..f2e95a4 --- /dev/null +++ b/root/blog/love_lua_photoshop_and_games/$order @@ -0,0 +1,4 @@ +final +animating +sheet +outside diff --git a/root/blog/ludum_dare_33_postmortem/$order b/root/blog/ludum_dare_33_postmortem/$order new file mode 100644 index 0000000..4072e61 --- /dev/null +++ b/root/blog/ludum_dare_33_postmortem/$order @@ -0,0 +1,2 @@ +smert +split diff --git a/root/blog/stencils_101/$order b/root/blog/stencils_101/$order new file mode 100644 index 0000000..80bf43b --- /dev/null +++ b/root/blog/stencils_101/$order @@ -0,0 +1,7 @@ +suits_final +killbill_progress +killbill_final +killbillstencil +balistencil_final +poster +technofist_final diff --git a/root/blog/stretching_gates/$order b/root/blog/stretching_gates/$order new file mode 100644 index 0000000..22512ed --- /dev/null +++ b/root/blog/stretching_gates/$order @@ -0,0 +1,5 @@ +case +stripboard +schematic +finished_case +crude diff --git a/root/blog/video_synth_research/$order b/root/blog/video_synth_research/$order new file mode 100644 index 0000000..604e582 --- /dev/null +++ b/root/blog/video_synth_research/$order @@ -0,0 +1,8 @@ +visualist +bent1 +LZX_reel +sketch_titler +bent2 +schematic +ich_bin_holz +mine diff --git a/root/experiments/$order b/root/experiments/$order new file mode 100644 index 0000000..6eca172 --- /dev/null +++ b/root/experiments/$order @@ -0,0 +1,5 @@ +tags +glitch_cube +torus4d +center_of_mass +parallax_panels diff --git a/root/experiments/parallax_panels/$order b/root/experiments/parallax_panels/$order new file mode 100644 index 0000000..c4fca74 --- /dev/null +++ b/root/experiments/parallax_panels/$order @@ -0,0 +1,2 @@ +picture +viewer diff --git a/root/experiments/parallax_panels/viewer/$order b/root/experiments/parallax_panels/viewer/$order new file mode 100644 index 0000000..1549b67 --- /dev/null +++ b/root/experiments/parallax_panels/viewer/$order @@ -0,0 +1 @@ +demo diff --git a/root/games/$order b/root/games/$order new file mode 100644 index 0000000..aeee1d5 --- /dev/null +++ b/root/games/$order @@ -0,0 +1,12 @@ +the_sacculi +zebra_painting +gtglg +the_monster_within +IYNX +vision-training-kit +curved_curse +two_shooting_stars +moving_out +channel_83 +plonat_atek +lorem_ipsum diff --git a/root/games/IYNX/$order b/root/games/IYNX/$order new file mode 100644 index 0000000..e46078b --- /dev/null +++ b/root/games/IYNX/$order @@ -0,0 +1,6 @@ +cryptex +teaser +pin_pad +pictures +ui_demo +boot_sequence diff --git a/root/games/IYNX/pictures/$order b/root/games/IYNX/pictures/$order new file mode 100644 index 0000000..8a44d99 --- /dev/null +++ b/root/games/IYNX/pictures/$order @@ -0,0 +1,6 @@ +ui_menu +c +ui_sample +d +a +b diff --git a/root/games/plonat_atek/$order b/root/games/plonat_atek/$order new file mode 100644 index 0000000..f1b9bd1 --- /dev/null +++ b/root/games/plonat_atek/$order @@ -0,0 +1,3 @@ +itch_page +video +pictures diff --git a/root/games/plonat_atek/pictures/$order b/root/games/plonat_atek/pictures/$order new file mode 100644 index 0000000..934d2fd --- /dev/null +++ b/root/games/plonat_atek/pictures/$order @@ -0,0 +1,3 @@ +setup +amaze +mockup diff --git a/root/games/text$moonscript -> fn -> mmm$dom.moon b/root/games/text$moonscript -> fn -> mmm$dom.moon index 70d2636..55e93a6 100644 --- a/root/games/text$moonscript -> fn -> mmm$dom.moon +++ b/root/games/text$moonscript -> fn -> mmm$dom.moon @@ -11,7 +11,7 @@ import ropairs from require 'mmm.ordered' children = for k, child in ropairs games desc = child\gett 'description: mmm/dom' jam = if link = child\get 'jam: mmm/dom' - span '[', link, ']', style: { float: 'right', color: 'var(--gray-dark)' } + span '[', link, ']', style: float: 'right', clear: 'right', color: 'var(--gray-dark)' li (link_to child), ': ', desc, jam diff --git a/root/projects/$order b/root/projects/$order new file mode 100644 index 0000000..5153662 --- /dev/null +++ b/root/projects/$order @@ -0,0 +1,9 @@ +themer +btrktrl +chimpanzee_bukkaque +HowDoIOS +VJmidiKit +iii-telefoni +demoloops +gayngine +vcv_mods diff --git a/root/projects/VJmidiKit/$order b/root/projects/VJmidiKit/$order new file mode 100644 index 0000000..6697bc5 --- /dev/null +++ b/root/projects/VJmidiKit/$order @@ -0,0 +1,11 @@ +tomcat +pineapple +boxy_visualist +boxy +jam +pillars +tomcat_tunnel +stills +kaleidoscope +dancing_pineapple +boxy_dnb diff --git a/root/projects/btrktrl/$order b/root/projects/btrktrl/$order new file mode 100644 index 0000000..c804056 --- /dev/null +++ b/root/projects/btrktrl/$order @@ -0,0 +1,13 @@ +pcb_glamour_connector +pcb_dev_configuration +knobs_testing +pcb_glamour_top +pcb_glamour +proto_rgb +proto_spi +knobs_all +proto_encoder +pcb_glamour_far +pcb_osc +pcb_glamour_close +pcb_dev_encoder diff --git a/root/projects/demoloops/$order b/root/projects/demoloops/$order new file mode 100644 index 0000000..b98a31c --- /dev/null +++ b/root/projects/demoloops/$order @@ -0,0 +1,16 @@ +toroid +squaregrid +zoom +koch +triangles +twisted +cube +planetary +flipping +weekly3 +dots +shutter +goldfish +divide +circle +fracture diff --git a/root/projects/demoloops/squaregrid/$order b/root/projects/demoloops/squaregrid/$order new file mode 100644 index 0000000..7ec8787 --- /dev/null +++ b/root/projects/demoloops/squaregrid/$order @@ -0,0 +1,3 @@ +rotated +overlaid +rounded diff --git a/root/projects/iii-telefoni/$order b/root/projects/iii-telefoni/$order new file mode 100644 index 0000000..d69cdf5 --- /dev/null +++ b/root/projects/iii-telefoni/$order @@ -0,0 +1,2 @@ +boxes +heads diff --git a/root/static/$order b/root/static/$order new file mode 100644 index 0000000..1c079db --- /dev/null +++ b/root/static/$order @@ -0,0 +1,4 @@ +highlight-pack +style +fengari-web +mmm -- cgit v1.2.3 From 16232a2509a87a900b69b2d0f826a2e3edec3f96 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 1 Nov 2019 13:48:24 +0100 Subject: add fileder ordering in stores.web, fileder, browser --- build/server.moon | 18 +++++++++++++++--- mmm/mmmfs/browser.moon | 4 ++-- mmm/mmmfs/fileder.moon | 6 ++++++ mmm/mmmfs/stores/web.moon | 3 +++ 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/build/server.moon b/build/server.moon index 395b903..a2d6c71 100644 --- a/build/server.moon +++ b/build/server.moon @@ -138,7 +138,18 @@ class Server @store\update_facet path, facet.name, facet.type, value 200, 'ok' else - 501, "not implemented" + cmd, args = value\match '^([^\n]+)\n(.*)' + switch cmd + when 'swap' + child_a, child_b = args\match '^([^\n]+)\n([^\n]+)$' + assert child_a and child_b, "invalid arguments" + + @store\swap_fileders path, child_a, child_b + 200, 'ok' + when nil + 400, "invalid request" + else + 501, "unknown command #{cmd}" when 'DELETE' if facet @store\remove_facet path, facet.name, facet.type @@ -175,8 +186,9 @@ class Server res = headers.new! response_type = if status > 299 then 'text/plain' - else if facet.type == 'text/html+interactive' then 'text/html' - else facet.type + else if facet and facet.type == 'text/html+interactive' then 'text/html' + else if facet then facet.type + else 'text/plain' res\append ':status', tostring status res\append 'content-type', response_type diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index 6020eb7..e06364c 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -279,11 +279,11 @@ class Browser span '- ', (link_to child, code name), style: flex: 1 button '↑', disabled: i == 1, onclick: (_, e) -> - fileder\reorder_child name, i - 1 + fileder\swap_children i, i - 1 @refresh true button '↓', disabled: i == num, onclick: (_, e) -> - fileder\reorder_child name, i + 1 + fileder\swap_children i, i + 1 @refresh true button 'rm', onclick: (_, e) -> diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index b42c6dd..871f46f 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -79,6 +79,7 @@ class Fileder __newindex: (t, k, child) -> rawset t, k, child + return if child.path if @path == '/' child\mount '/' @@ -318,6 +319,11 @@ class Fileder assert removed, "no such child fileder" @store\remove_fileder removed.path + swap_children: (ia, ib) => + a, b = @children[ia], @children[ib] + @store\swap_fileders @path, (a\gett 'name: alpha'), (b\gett 'name: alpha') + @children[ia], @children[ib] = b, a + __tostring: => "Fileder:#{@path}" { diff --git a/mmm/mmmfs/stores/web.moon b/mmm/mmmfs/stores/web.moon index b498d79..ddbd74d 100644 --- a/mmm/mmmfs/stores/web.moon +++ b/mmm/mmmfs/stores/web.moon @@ -77,6 +77,9 @@ class WebStore extends Store @log "moving fileder #{path} -> #{next_parent}/" error "not implemented" + swap_fileders: (parent, child_a, child_b) => + req 'PUT', "#{@host .. parent}/", "swap\n#{child_a}\n#{child_b}" + -- facets list_facets: (path) => coroutine.wrap -> -- cgit v1.2.3 From b897f7705e437a776d18bb3a8c6725d009d31111 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 1 Nov 2019 14:08:37 +0100 Subject: fix inspector --- mmm/mmmfs/browser.moon | 10 +++++++++- scss/_browser.scss | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index e06364c..9cda4b2 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -213,8 +213,10 @@ class Browser @inspect_err = ReactiveVar! with div class: 'view inspector' + -- nav \append nav { span 'inspector' + @inspect_prop\map (current) -> current = current and current\tostring! fileder = @fileder\get! @@ -224,7 +226,8 @@ class Browser return if facet == '' @inspect_prop\set Key facet - with select :onchange \append option '(none)', value: '', disabled: true, selected: not value + with select :onchange + \append option '(none)', value: '', disabled: true, selected: not value if fileder for value in pairs fileder.facet_keys \append option value, :value, selected: value == current @@ -245,6 +248,8 @@ class Browser button 'close', onclick: (_, e) -> @inspect\set false } + + -- error / content \append with div class: @inspect_err\map (e) -> if e then 'error-wrap' else 'error-wrap empty' \append span "an error occured while rendering this view:" \append @inspect_err @@ -258,7 +263,10 @@ class Browser assert conversions, "cannot cast '#{key.type}'" apply_conversions conversions, value, @, prop + -- children \append nav { + class: 'thing' + span 'children' button 'add', onclick: (_, e) -> name = window\prompt "please enter the name of the child fileder:", 'unnamed_fileder' diff --git a/scss/_browser.scss b/scss/_browser.scss index f39e1df..adf9dd1 100644 --- a/scss/_browser.scss +++ b/scss/_browser.scss @@ -77,6 +77,10 @@ white-space: nowrap; } + &.thin > * { + margin: 0.5em 1em; + } + > .inspect-btn { @include media-small() { display: none; } } -- cgit v1.2.3 From d3eafbcb25b15fc975f5005a3d9f1f69f430cd20 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 1 Nov 2019 14:39:46 +0100 Subject: add ba_log entry 2019-11-01 --- root/articles/mmmfs/ba_log/$order | 1 + root/articles/mmmfs/ba_log/2019-11-01/$order | 1 + .../mmmfs/ba_log/2019-11-01/demo/video$webm.webm | Bin 0 -> 9968238 bytes .../articles/mmmfs/ba_log/2019-11-01/text$markdown.md | 18 ++++++++++++++++++ 4 files changed, 20 insertions(+) create mode 100644 root/articles/mmmfs/ba_log/2019-11-01/$order create mode 100644 root/articles/mmmfs/ba_log/2019-11-01/demo/video$webm.webm create mode 100644 root/articles/mmmfs/ba_log/2019-11-01/text$markdown.md diff --git a/root/articles/mmmfs/ba_log/$order b/root/articles/mmmfs/ba_log/$order index 600a4d9..18fda81 100644 --- a/root/articles/mmmfs/ba_log/$order +++ b/root/articles/mmmfs/ba_log/$order @@ -9,3 +9,4 @@ 2019-10-26 2019-10-27 2019-10-29 +2019-11-01 diff --git a/root/articles/mmmfs/ba_log/2019-11-01/$order b/root/articles/mmmfs/ba_log/2019-11-01/$order new file mode 100644 index 0000000..1549b67 --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-11-01/$order @@ -0,0 +1 @@ +demo diff --git a/root/articles/mmmfs/ba_log/2019-11-01/demo/video$webm.webm b/root/articles/mmmfs/ba_log/2019-11-01/demo/video$webm.webm new file mode 100644 index 0000000..1463897 Binary files /dev/null and b/root/articles/mmmfs/ba_log/2019-11-01/demo/video$webm.webm differ diff --git a/root/articles/mmmfs/ba_log/2019-11-01/text$markdown.md b/root/articles/mmmfs/ba_log/2019-11-01/text$markdown.md new file mode 100644 index 0000000..d40862d --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-11-01/text$markdown.md @@ -0,0 +1,18 @@ +In the last two days I implemented the remaining features for full editing support in the browser: + +- support for adding, removing facets in the inspector \[[`dc08e26`][dc08e26]\] +- support for adding, removing fileders in the inspector \[[`ff9ee8e`][ff9ee8e]\] +- implemented the API for reordering fileders as mentioned in [`2019-10-26`][2019-10-26] \[[`053e607`][053e607]\] +- support for reordering fileders in the inspector \[[`16232a2`][16232a2]\] + +Here is a short demo video of these features: + + + +As usual, this can be tried out immediately at [`sandbox.s-ol.nu`](//sandbox.s-ol.nu) + +[2019-10-26]: /articles/mmmfs/ba_log/2019-10-26/ +[dc08e26]: https://git.s-ol.nu/mmm/commit/dc08e262cd53a48480a88235aa58500f0638ad79/ +[ff9ee8e]: https://git.s-ol.nu/mmm/commit/ff9ee8e99cd5f5c420ba0501c335ac18f1b10769/ +[053e607]: https://git.s-ol.nu/mmm/commit/053e607a49989b2d4491c20ff14c839b7161d713/ +[16232a2]: https://git.s-ol.nu/mmm/commit/16232a2509a87a900b69b2d0f826a2e3edec3f96/ -- cgit v1.2.3 From 50ac388d23d4f59013c4499912d1a34bbd86f92d Mon Sep 17 00:00:00 2001 From: s-ol Date: Wed, 6 Nov 2019 14:52:56 +0100 Subject: fix PUT : --- build/server.moon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/server.moon b/build/server.moon index a2d6c71..b95b396 100644 --- a/build/server.moon +++ b/build/server.moon @@ -170,7 +170,7 @@ class Server path_facet or= path path, facet = path_facet\match '(.*)/([^/]*)' - facet = if facet == '' and method ~= 'GET' and method ~= 'HEAD' + facet = if facet == '' and type == '' and method ~= 'GET' and method ~= 'HEAD' nil else type or= 'text/html+interactive' -- cgit v1.2.3 From 51e2b88f641a0283e5f84ac3e68654fd7e5d883c Mon Sep 17 00:00:00 2001 From: s-ol Date: Sun, 17 Nov 2019 19:36:11 +0100 Subject: fix navlinks --- mmm/mmmfs/browser.moon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index 9cda4b2..80b47c4 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -99,7 +99,7 @@ class Browser .node.innerHTML = '' \append span 'path: ', @path\map (path) -> with div class: 'path', style: { display: 'inline-block' } path_segment = (name, href) -> - a name, :href, onclick: (_, e) -> + a name, href: "#{href}/", onclick: (_, e) -> e\preventDefault! @navigate href -- cgit v1.2.3 From 5ec1fe2fc943ad4123fac138de70d4152e8b341d Mon Sep 17 00:00:00 2001 From: s-ol Date: Mon, 25 Nov 2019 15:54:28 +0100 Subject: add pinwall example --- mmm/mmmfs/plugins/init.moon | 26 +---- mmm/mmmfs/plugins/json.moon | 56 ++++++++++ root/articles/mmmfs/examples/$order | 1 + root/articles/mmmfs/examples/pinwall/$order | 3 + .../mmmfs/examples/pinwall/image/image$png.png | Bin 0 -> 128929 bytes .../examples/pinwall/image/pinwall_info: text$json | 1 + .../pinwall/text$moonscript -> fn -> mmm$dom.moon | 120 +++++++++++++++++++++ .../examples/pinwall/text/pinwall_info: text$json | 1 + .../mmmfs/examples/pinwall/text/text$plain.txt | 4 + .../mmmfs/examples/pinwall/title: text$plain | 1 + .../mmmfs/examples/pinwall/video/URL -> video$mp4 | 1 + .../examples/pinwall/video/pinwall_info: text$json | 1 + 12 files changed, 190 insertions(+), 25 deletions(-) create mode 100644 mmm/mmmfs/plugins/json.moon create mode 100644 root/articles/mmmfs/examples/pinwall/$order create mode 100644 root/articles/mmmfs/examples/pinwall/image/image$png.png create mode 100644 root/articles/mmmfs/examples/pinwall/image/pinwall_info: text$json create mode 100644 root/articles/mmmfs/examples/pinwall/text$moonscript -> fn -> mmm$dom.moon create mode 100644 root/articles/mmmfs/examples/pinwall/text/pinwall_info: text$json create mode 100644 root/articles/mmmfs/examples/pinwall/text/text$plain.txt create mode 100644 root/articles/mmmfs/examples/pinwall/title: text$plain create mode 100644 root/articles/mmmfs/examples/pinwall/video/URL -> video$mp4 create mode 100644 root/articles/mmmfs/examples/pinwall/video/pinwall_info: text$json diff --git a/mmm/mmmfs/plugins/init.moon b/mmm/mmmfs/plugins/init.moon index 5afd7be..c31cd57 100644 --- a/mmm/mmmfs/plugins/init.moon +++ b/mmm/mmmfs/plugins/init.moon @@ -187,31 +187,6 @@ converts = { cost: 5 transform: (_, fileder, key) => "#{fileder.path}/#{key.name}:#{@from}" } - { - inp: 'table', - out: 'text/json', - cost: 2 - transform: do - tojson = (obj) -> - switch type obj - when 'string' - string.format '%q', obj - when 'table' - if obj[1] or not next obj - "[#{table.concat [tojson c for c in *obj], ','}]" - else - "{#{table.concat ["#{tojson k}: #{tojson v}" for k,v in pairs obj], ', '}}" - when 'number' - tostring obj - when 'boolean' - tostring obj - when 'nil' - 'null' - else - error "unknown type '#{type obj}'" - - (val) => tojson val - } { inp: 'table', out: 'mmm/dom', @@ -258,6 +233,7 @@ add_converts = (module) -> table.insert editors, editor add_converts 'code' +add_converts 'json' add_converts 'markdown' add_converts 'mermaid' add_converts 'twitter' diff --git a/mmm/mmmfs/plugins/json.moon b/mmm/mmmfs/plugins/json.moon new file mode 100644 index 0000000..cbcff46 --- /dev/null +++ b/mmm/mmmfs/plugins/json.moon @@ -0,0 +1,56 @@ +encode = (obj) -> + switch type obj + when 'string' + string.format '%q', obj + when 'table' + if obj[1] or not next obj + "[#{table.concat [encode c for c in *obj], ','}]" + else + "{#{table.concat ["#{encode k}: #{encode v}" for k,v in pairs obj], ', '}}" + when 'number' + tostring obj + when 'boolean' + tostring obj + when 'nil' + 'null' + else + error "unknown type '#{type obj}'" + +decode = if MODE == 'CLIENT' + import Array, Object, JSON from js.global + + fix = (val) -> + switch type val + when 'userdata' + if Array\isArray val + [fix x for x in js.of val] + else + {(fix e[0]), (fix e[1]) for e in js.of Object\entries(val)} + else + val + + encode + decode = (str) -> fix JSON\parse str +else if cjson = require 'cjson' + cjson.decode +else + warn 'only partial JSON support, please install cjson' + + +{ + converts: { + { + inp: 'table', + out: 'text/json', + cost: 2 + transform: (val) => encode val + } + if decode + { + inp: 'text/json' + out: 'table' + cost: 1 + transform: (val) => decode val + } + } +} diff --git a/root/articles/mmmfs/examples/$order b/root/articles/mmmfs/examples/$order index 7428a7e..348f5fe 100644 --- a/root/articles/mmmfs/examples/$order +++ b/root/articles/mmmfs/examples/$order @@ -3,3 +3,4 @@ image markdown empty gallery +pinwall diff --git a/root/articles/mmmfs/examples/pinwall/$order b/root/articles/mmmfs/examples/pinwall/$order new file mode 100644 index 0000000..b8b054a --- /dev/null +++ b/root/articles/mmmfs/examples/pinwall/$order @@ -0,0 +1,3 @@ +image +text +video diff --git a/root/articles/mmmfs/examples/pinwall/image/image$png.png b/root/articles/mmmfs/examples/pinwall/image/image$png.png new file mode 100644 index 0000000..1628d99 Binary files /dev/null and b/root/articles/mmmfs/examples/pinwall/image/image$png.png differ diff --git a/root/articles/mmmfs/examples/pinwall/image/pinwall_info: text$json b/root/articles/mmmfs/examples/pinwall/image/pinwall_info: text$json new file mode 100644 index 0000000..74fba2c --- /dev/null +++ b/root/articles/mmmfs/examples/pinwall/image/pinwall_info: text$json @@ -0,0 +1 @@ +{"x": 35.0, "y": 209.0, "w": 205.0, "h": 155.0} \ No newline at end of file diff --git a/root/articles/mmmfs/examples/pinwall/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/examples/pinwall/text$moonscript -> fn -> mmm$dom.moon new file mode 100644 index 0000000..e611579 --- /dev/null +++ b/root/articles/mmmfs/examples/pinwall/text$moonscript -> fn -> mmm$dom.moon @@ -0,0 +1,120 @@ +import article, div from require 'mmm.dom' +import convert from require 'mmm.mmmfs.conversion' + +update_info = (fileder, x, y, w, h) -> + info = (fileder\get 'pinwall_info: table') or x: 100, y: 100, w: 300, h: 300 + info.x = x if x + info.y = y if y + info.w = w if w + info.h = h if h + + json = convert 'table', 'text/json', info, fileder, 'pinwall_info' + fileder\set 'pinwall_info: text/json', json + +CLIENT = MODE == 'CLIENT' + +=> + + pending = {} + observe = if CLIENT + map = {} + observer = js.new js.global.ResizeObserver, (_, entries) -> + for entry in js.of entries + if child = map[entry.target] + rect = entry.contentRect + pending[child] = -> update_info child, nil, nil, rect.width, rect.height + + (node, child) -> + map[node] = child + observer\observe node + + drag = nil + + children = for child in *@children + info = (child\get 'pinwall_info: table') or x: 100, y: 100, w: 300, h: 300 + wrapper = div { + style: + position: 'absolute' + padding: '10px' + resize: 'both' + overflow: 'hidden' + background: 'var(--gray-dark)' + border: '1px solid var(--gray-bright)' + + left: "#{info.x}px" + top: "#{info.y}px" + width: "#{info.w}px" + height: "#{info.h}px" + + -- handle for moving the child + div { + style: + top: '0' + left: '0' + right: '0' + height: '10px' + cursor: 'pointer' + position: 'absolute' + + onmousedown: CLIENT and (_, e) -> + node = e.target.parentElement + drag = { + :child + :node + + startX: tonumber node.style.left\match '(%d+)px' + startY: tonumber node.style.top\match '(%d+)px' + startMouseX: e.clientX + startMouseY: e.clientY + } + } + + -- child content + div { + style: + width: '100%' + height: '100%' + background: 'var(--white)' + + (child\gett 'mmm/dom') + } + } + + -- listen for resize events + observe wrapper, child if CLIENT + wrapper + + children.style = { + width: '1000px' + height: '500px' + } + + if CLIENT + children.onmousemove = (_, e) -> + return unless drag + + x = drag.startX + (e.clientX - drag.startMouseX) + y = drag.startY + (e.clientY - drag.startMouseY) + drag.node.style.left = "#{x}px" + drag.node.style.top = "#{y}px" + + children.onmouseup = (_, e) -> + for k, func in pairs pending + func! + pending = {} + + return unless drag + + x = drag.startX + (e.clientX - drag.startMouseX) + y = drag.startY + (e.clientY - drag.startMouseY) + update_info drag.child, x, y + drag = nil + + children.onmouseleave = (_, e) -> + return unless drag + + drag.node.style.left = "#{drag.startX}px" + drag.node.style.top = "#{drag.startY}px" + drag = nil + + article children diff --git a/root/articles/mmmfs/examples/pinwall/text/pinwall_info: text$json b/root/articles/mmmfs/examples/pinwall/text/pinwall_info: text$json new file mode 100644 index 0000000..d373545 --- /dev/null +++ b/root/articles/mmmfs/examples/pinwall/text/pinwall_info: text$json @@ -0,0 +1 @@ +{"x": 91.0, "y": 17.0, "w": 186.0, "h": 128.0} \ No newline at end of file diff --git a/root/articles/mmmfs/examples/pinwall/text/text$plain.txt b/root/articles/mmmfs/examples/pinwall/text/text$plain.txt new file mode 100644 index 0000000..8838e5a --- /dev/null +++ b/root/articles/mmmfs/examples/pinwall/text/text$plain.txt @@ -0,0 +1,4 @@ +This is a pinwall example. +Every box is a separate fileder. +The boxes can be rearranged and resized freely. +If the server is in read-write mode, the changes are saved persistently in real time. diff --git a/root/articles/mmmfs/examples/pinwall/title: text$plain b/root/articles/mmmfs/examples/pinwall/title: text$plain new file mode 100644 index 0000000..9d29c5d --- /dev/null +++ b/root/articles/mmmfs/examples/pinwall/title: text$plain @@ -0,0 +1 @@ +A pinwall diff --git a/root/articles/mmmfs/examples/pinwall/video/URL -> video$mp4 b/root/articles/mmmfs/examples/pinwall/video/URL -> video$mp4 new file mode 100644 index 0000000..6364771 --- /dev/null +++ b/root/articles/mmmfs/examples/pinwall/video/URL -> video$mp4 @@ -0,0 +1 @@ +https://file-examples.com/wp-content/uploads/2017/04/file_example_MP4_480_1_5MG.mp4 diff --git a/root/articles/mmmfs/examples/pinwall/video/pinwall_info: text$json b/root/articles/mmmfs/examples/pinwall/video/pinwall_info: text$json new file mode 100644 index 0000000..30c947e --- /dev/null +++ b/root/articles/mmmfs/examples/pinwall/video/pinwall_info: text$json @@ -0,0 +1 @@ +{"x": 263.0, "y": 210.0, "w": 353.0, "h": 295.0} \ No newline at end of file -- cgit v1.2.3 From 67de3b2115e007de4b2bca986625654d18549e4d Mon Sep 17 00:00:00 2001 From: s-ol Date: Mon, 25 Nov 2019 15:54:42 +0100 Subject: document new dependency --- README.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1319914..7c13121 100644 --- a/README.md +++ b/README.md @@ -42,13 +42,21 @@ You can do this with the following command: $ tup monitor -f -a ### Dependencies -You will need: + +Required dependencies: - [MoonScript][moonscript]: `luarocks install moonscript` -- [lua-sqlite3](https://luarocks.org/modules/moteus/sqlite3): `luarocks install sqlite3` - [lua-http](https://github.com/daurnimator/lua-http): `luarocks install http` -- [discount](https://luarocks.org/modules/craigb/discount): `luarocks install discount` (requires libmarkdown2) -- [busted](https://olivinelabs.com/busted/): `luarocks install busted` (for testing only) + +For unit tests: + +- [busted](https://olivinelabs.com/busted/): `luarocks install busted` + +Not required but recommended: + +- [lua-sqlite3](https://luarocks.org/modules/moteus/sqlite3): `luarocks install sqlite3` (for SQLite3 backend) +- [lua-cjson](https://www.kyne.com.au/~mark/software/lua-cjson.php): `luarocks install lua-cjson 2.1.0-1` (for server-side JSON support) +- [discount](https://luarocks.org/modules/craigb/discount): `luarocks install discount` (requires libmarkdown2, for Markdown support) ### Live Reloading (during development) [entr][entr] is useful for reloading the dev server when code outside the root changes: -- cgit v1.2.3 From 784e0b74f112c1b6b395a02e45eb1323c2acfe21 Mon Sep 17 00:00:00 2001 From: s-ol Date: Mon, 25 Nov 2019 21:27:45 +0100 Subject: add ba_log entry 2019-11-25 --- root/articles/mmmfs/ba_log/$order | 1 + .../mmmfs/ba_log/2019-11-01/text$markdown.md | 2 +- root/articles/mmmfs/ba_log/2019-11-25/$order | 1 + .../mmmfs/ba_log/2019-11-25/demo/video$webm.webm | Bin 0 -> 1380724 bytes .../mmmfs/ba_log/2019-11-25/text$markdown.md | 89 +++++++++++++++++++++ 5 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 root/articles/mmmfs/ba_log/2019-11-25/$order create mode 100644 root/articles/mmmfs/ba_log/2019-11-25/demo/video$webm.webm create mode 100644 root/articles/mmmfs/ba_log/2019-11-25/text$markdown.md diff --git a/root/articles/mmmfs/ba_log/$order b/root/articles/mmmfs/ba_log/$order index 18fda81..564679b 100644 --- a/root/articles/mmmfs/ba_log/$order +++ b/root/articles/mmmfs/ba_log/$order @@ -10,3 +10,4 @@ 2019-10-27 2019-10-29 2019-11-01 +2019-11-25 diff --git a/root/articles/mmmfs/ba_log/2019-11-01/text$markdown.md b/root/articles/mmmfs/ba_log/2019-11-01/text$markdown.md index d40862d..afcaf0a 100644 --- a/root/articles/mmmfs/ba_log/2019-11-01/text$markdown.md +++ b/root/articles/mmmfs/ba_log/2019-11-01/text$markdown.md @@ -7,7 +7,7 @@ In the last two days I implemented the remaining features for full editing suppo Here is a short demo video of these features: - + As usual, this can be tried out immediately at [`sandbox.s-ol.nu`](//sandbox.s-ol.nu) diff --git a/root/articles/mmmfs/ba_log/2019-11-25/$order b/root/articles/mmmfs/ba_log/2019-11-25/$order new file mode 100644 index 0000000..1549b67 --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-11-25/$order @@ -0,0 +1 @@ +demo diff --git a/root/articles/mmmfs/ba_log/2019-11-25/demo/video$webm.webm b/root/articles/mmmfs/ba_log/2019-11-25/demo/video$webm.webm new file mode 100644 index 0000000..bdf9d9c Binary files /dev/null and b/root/articles/mmmfs/ba_log/2019-11-25/demo/video$webm.webm differ diff --git a/root/articles/mmmfs/ba_log/2019-11-25/text$markdown.md b/root/articles/mmmfs/ba_log/2019-11-25/text$markdown.md new file mode 100644 index 0000000..48a0bb4 --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-11-25/text$markdown.md @@ -0,0 +1,89 @@ +There was a longer break in development of the projects as I have been focusing on the thesis, +where progress is not represented accurately in the repository. + +There was also some progress on featurse that haven't been tidied up and committed yet, +such as drag'n'drop / direct file upload. Those features will probably get their own post sometime soon. + +Today I spent some time to implement one of the example use-cases that will be part of the theoretical text as well, +[the 'pinwall' demo][pinwall] \[[`5ec1fe2`][5ec1fe2]\]. + +The Pinwall example renders all its children as resizeable and movable boxes that can be freely positioned on a canvas: + + + +Any changes to the box positions and sizes are saved persistently as a `pinwall_info` facet on each child. +For example the size and coordinates of the image can be found at [`image/pinwall_info: text/json`][info]. + +Rendering the children themselves is pretty easy: + +```moon +import article, div from require 'mmm.dom' +import convert from require 'mmm.mmmfs.conversion' + +update_info = (fileder, x, y, w, h) -> + info = (fileder\get 'pinwall_info: table') or x: 100, y: 100, w: 300, h: 300 + info.x = x if x + info.y = y if y + info.w = w if w + info.h = h if h + + json = convert 'table', 'text/json', info, fileder, 'pinwall_info' + fileder\set 'pinwall_info: text/json', json + +=> + observe = ... -- (ommited - calls `update_info` when child is resized) + + children = for child in *@children + info = (child\get 'pinwall_info: table') or x: 100, y: 100, w: 300, h: 300 + wrapper = div { + style: + position: 'absolute' + -- (more styling omitted here) + + left: "#{info.x}px" + top: "#{info.y}px" + width: "#{info.w}px" + height: "#{info.h}px" + + -- handle for moving the child + div { + style: + -- (styling omitted here) + + onmousedown: ... -- (omitted) + } + + -- child content + div { + style: + width: '100%' + height: '100%' + background: 'var(--white)' + + (child\gett 'mmm/dom') + } + } + + observe wrapper, child + + wrapper + + children.style = { + width: '1000px' + height: '500px' + } + + children.onmouseup = ... -- (omitted) + children.onmousemove = ... -- (omitted) + children.onmouseleave = ... -- (omitted) + + article children +``` + +[The rest of the code][source] is just about catching the events when the mouse is clicked/release/moved and when a child is resized, +and then calling `update_info` as appropriate. + +[info]: /articles/mmmfs/examples/pinwall/image/pinwall_info:%20text/html+interactive +[pinwall]: /articles/mmmfs/examples/pinwall/ +[source]: https://git.s-ol.nu/mmm/blob/5ec1fe2fc943ad4123fac138de70d4152e8b341d/root/articles/mmmfs/examples/pinwall/text%24moonscript%20-%3E%20fn%20-%3E%20mmm%24dom.moon +[5ec1fe2]: https://git.s-ol.nu/mmm/blob/5ec1fe2fc943ad4123fac138de70d4152e8b341d/ -- cgit v1.2.3 From 9e26a2d9f1fb6950ee75d7f0d16eeaacb6d76eb8 Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 26 Nov 2019 12:08:31 +0100 Subject: add cjson to Dockerfile --- Dockerfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index ef1246b..a4bc421 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,9 +7,10 @@ RUN apt-get update && \ build-essential m4 tup sassc \ libmarkdown2-dev libsqlite3-dev libssl-dev RUN luarocks install discount DISCOUNT_INCDIR=/usr/include/x86_64-linux-gnu -RUN luarocks install moonscript -RUN luarocks install sqlite3 -RUN luarocks install http +RUN luarocks install sqlite3 && \ + luarocks install moonscript && \ + luarocks install http && \ + luarocks install lua-cjson 2.1.0-1 COPY . /code WORKDIR /code -- cgit v1.2.3 From bde1fae7c3497bbe10eb67fa2c2c6d46d5ad0478 Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 26 Nov 2019 12:18:31 +0100 Subject: some fixes in aspect-ratios --- .../interactive/_base: text$moonscript -> table.moon | 16 ++++++++-------- root/blog/aspect_ratios/text$markdown.md | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/root/blog/aspect_ratios/interactive/_base: text$moonscript -> table.moon b/root/blog/aspect_ratios/interactive/_base: text$moonscript -> table.moon index f47e03f..419eef0 100644 --- a/root/blog/aspect_ratios/interactive/_base: text$moonscript -> table.moon +++ b/root/blog/aspect_ratios/interactive/_base: text$moonscript -> table.moon @@ -8,10 +8,10 @@ if MODE ~= 'CLIENT' resize: 'horizontal' overflow: 'hidden' - width: '576px' - height: '324px' - 'min-width': '324px' - 'max-width': '742px' + width: '480px' + height: '270px' + 'min-width': '270px' + 'max-width': '100%' margin: 'auto' padding: '10px' @@ -42,10 +42,10 @@ class UIDemo extends CanvasApp resize: 'horizontal' overflow: 'hidden' - width: '576px' - height: '324px' - minWidth: '324px' - maxWidth: '742px' + width: '480px' + height: '270px' + minWidth: '270px' + maxWidth: '100%' margin: 'auto' padding: '10px' diff --git a/root/blog/aspect_ratios/text$markdown.md b/root/blog/aspect_ratios/text$markdown.md index dea0249..2284317 100644 --- a/root/blog/aspect_ratios/text$markdown.md +++ b/root/blog/aspect_ratios/text$markdown.md @@ -42,7 +42,7 @@ The problem with this is that it simply doesn't look very good. When the ratio but otherwise the empty space makes the screen look empty (especially if there are system UI elements next to it). ## step two: `perforate` -So how can this be imroved? We would like to use the unused space on the x or y axis, but we can't just scale everything up, +So how can this be improved? We would like to use the unused space on the x or y axis, but we can't just scale everything up, or we would start cropping important pieces of UI. Stretching the game to fill the screen also doesn't work for obvious reasons. To proceed, the UI has to be 'perforated' into different sections that are independent from each other. -- cgit v1.2.3 From 19b4e92138bbcef9cde90a12141530e1bd6aa13a Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 17 Dec 2019 20:26:29 +0100 Subject: add sidenote support --- .../mmmfs/ba_log/2019-10-09/text$markdown.md | 2 +- .../mmmfs/text$moonscript -> fn -> mmm$dom.moon | 2 +- scss/_sidenotes.scss | 31 ++++++++++++++++++++++ scss/main.scss | 1 + 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 scss/_sidenotes.scss diff --git a/root/articles/mmmfs/ba_log/2019-10-09/text$markdown.md b/root/articles/mmmfs/ba_log/2019-10-09/text$markdown.md index 9fec148..702620d 100644 --- a/root/articles/mmmfs/ba_log/2019-10-09/text$markdown.md +++ b/root/articles/mmmfs/ba_log/2019-10-09/text$markdown.md @@ -3,7 +3,7 @@ and made the server load the fileder tree when it receives a request for content This means that I can work on the content again and see changes in the browser without restarting the server every time \[[`97bc4a0`][97bc4a0]\], This feature should be made unnecessary by the in-page editing feature, but until then it's important for my workflow. -I also started cleaning up the mmmfs article a bit, and integrating this project log in a way that will make it available online soon5f78953becd422126a528b2c31dd611cb0b29ef6 +I also started cleaning up the mmmfs article a bit, and integrating this project log in a way that will make it available online soon. [86bbe80]: https://git.s-ol.nu/mmm/commit/86bbe805a7ec49a8b891412713ea43d6e46d0d73/ [97bc4a0]: https://git.s-ol.nu/mmm/commit/97bc4a0d8d866026905eac6f0ba08b75f166219a/ diff --git a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon index eac77c6..f6c9cca 100644 --- a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon @@ -7,7 +7,7 @@ import article, h1, h2, h3, section, p, div, a, sup, ol, li, span, code, pre, br from html import moon from (require 'mmm.highlighting').languages - article with _this = style: { margin: 'auto', 'max-width': '750px' } + article with _this = class: 'sidenote-container', style: { 'max-width': '640px' } append = (a) -> table.insert _this, a footnote, getnotes = do diff --git a/scss/_sidenotes.scss b/scss/_sidenotes.scss new file mode 100644 index 0000000..8579ba1 --- /dev/null +++ b/scss/_sidenotes.scss @@ -0,0 +1,31 @@ +$sidenote-width: 14rem; + +.sidenote-container { + margin-right: $sidenote-width + 1rem; + + @include media-medium { + margin: auto; + } + + .sidenote { + position: absolute; + box-sizing: border-box; + + width: $sidenote-width; + right: -$sidenote-width - 2rem; + padding: 0 1rem; + + color: $gray-dark; + border-top: 1px solid $gray-dark; + font-size: 0.8em; + + @include media-medium { + width: initial; + position: initial; + right: initial; + + border-bottom: 1px solid $gray-dark; + margin: 0.5rem 0; + } + } +} diff --git a/scss/main.scss b/scss/main.scss index 08ce942..efec299 100644 --- a/scss/main.scss +++ b/scss/main.scss @@ -6,4 +6,5 @@ @import 'footer'; @import 'browser'; @import 'content'; +@import 'sidenotes'; @import 'canvasapp'; -- cgit v1.2.3 From a4038511560d408827cdea7e2e99751496687181 Mon Sep 17 00:00:00 2001 From: s-ol Date: Wed, 18 Dec 2019 00:46:04 +0100 Subject: cites plugin --- build/server.moon | 6 ++- mmm/mmmfs/plugins/cites.moon | 26 ++++++++++++ mmm/mmmfs/plugins/init.moon | 26 +++++++++++- mmm/mmmfs/util.moon | 49 ++++++++++++++++------ root/articles/mmmfs/$order | 2 +- root/articles/mmmfs/references/$order | 2 + root/articles/mmmfs/references/text$markdown.md | 0 .../text$moonscript -> fn -> mmm$dom.moon | 6 +++ .../articles/mmmfs/references/unix/URL -> cite$acm | 1 + .../mmmfs/references/xerox-star/URL -> cite$acm | 1 + scss/_content.scss | 14 ++++++- 11 files changed, 117 insertions(+), 16 deletions(-) create mode 100644 mmm/mmmfs/plugins/cites.moon create mode 100644 root/articles/mmmfs/references/$order delete mode 100644 root/articles/mmmfs/references/text$markdown.md create mode 100644 root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon create mode 100644 root/articles/mmmfs/references/unix/URL -> cite$acm create mode 100644 root/articles/mmmfs/references/xerox-star/URL -> cite$acm diff --git a/build/server.moon b/build/server.moon index b95b396..7c0ff46 100644 --- a/build/server.moon +++ b/build/server.moon @@ -99,7 +99,11 @@ class Server switch method when 'GET', 'HEAD' - fileder = Fileder @store, path + root = Fileder @store + export BROWSER + BROWSER = :root + fileder = root\walk path -- Fileder @store, path + if not fileder -- fileder not found return 404, "fileder '#{path}' not found" diff --git a/mmm/mmmfs/plugins/cites.moon b/mmm/mmmfs/plugins/cites.moon new file mode 100644 index 0000000..01f5b3f --- /dev/null +++ b/mmm/mmmfs/plugins/cites.moon @@ -0,0 +1,26 @@ +import div, i from require 'mmm.dom' + +{ + converts: { + { + inp: 'URL -> cite/acm' + out: 'URL -> text/bibtex' + cost: 0.5 + transform: (url) => + id = assert (url\match '//dl%.acm%.org/citation%.cfm%?id=(%d+)'), "couldn't parse cite/acm URL: '#{url}'" + "https://cors-anywhere.herokuapp.com/https://dl.acm.org/exportformats.cfm?id=#{id}&expformat=bibtex" + } + { + inp: 'text/bibtex' + out: 'mmm/dom' + cost: 1 + transform: (src) => + type, key, kv = src\match '@(%w+){(.-),(.*)}' + info = {} + for key, val in kv\gmatch '([a-z]-)%s*=%s*{(.-)}' + info[key] = val + + div "#{info.author} (#{info.year}),", (i info.title), ". #{info.publisher}" + } + } +} diff --git a/mmm/mmmfs/plugins/init.moon b/mmm/mmmfs/plugins/init.moon index c31cd57..1650c3a 100644 --- a/mmm/mmmfs/plugins/init.moon +++ b/mmm/mmmfs/plugins/init.moon @@ -95,6 +95,7 @@ converts = { when 'facet' then facet = val when 'nolink' then opts.nolink = true when 'inline' then opts.inline = true + when 'raw' then opts.raw = true else warn "unkown attribute '#{key}=\"#{val}\"' in " embed path, facet, fileder, opts @@ -113,10 +114,12 @@ converts = { facet = js_fix element\getAttribute 'facet' nolink = js_fix element\getAttribute 'nolink' inline = js_fix element\getAttribute 'inline' + raw = js_fix element\getAttribute 'raw' desc = js_fix element.innerText desc = nil if desc == '' - element\replaceWith embed path or '', facet or '', fileder, { :nolink, :inline, :desc } + opts = :nolink, :inline, :raw, :desc + element\replaceWith embed path or '', facet or '', fileder, opts embeds = \getElementsByTagName 'mmm-link' embeds = [embeds[i] for i=0, embeds.length - 1] @@ -181,6 +184,26 @@ converts = { -- out: 'mmm/dom', -- transform: single code -- } + { + inp: 'URL -> (.+)', + out: '%1', + cost: 4, + transform: do + if MODE == 'CLIENT' + (uri) => + request = js.new js.global.XMLHttpRequest + request\open 'GET', uri, false + request\send js.null + + assert request.status == 200, "unexpected status code: #{request.status}" + request.responseText + else + (uri) => + request = require 'http.request' + req = request.new_from_uri uri + headers, stream = req\go 8 + assert stream\get_body_as_string! + } { inp: '(.+)', out: 'URL -> %1', @@ -238,6 +261,7 @@ add_converts 'markdown' add_converts 'mermaid' add_converts 'twitter' add_converts 'youtube' +add_converts 'cites' if MODE == 'SERVER' ok, moon = pcall require, 'moonscript.base' diff --git a/mmm/mmmfs/util.moon b/mmm/mmmfs/util.moon index 0e57f93..970dd42 100644 --- a/mmm/mmmfs/util.moon +++ b/mmm/mmmfs/util.moon @@ -12,14 +12,34 @@ tourl = (path) -> (elements) -> import a, div, span, pre from elements - find_fileder = (fileder, origin) -> + find_fileder = (fileder, origin) -> if 'string' == type fileder - if '/' == fileder\sub 1, 1 - assert BROWSER and BROWSER.root, "cannot resolve absolute path '#{fileder}' without BROWSER and root set!" - assert (BROWSER.root\walk fileder), "couldn't resolve path '#{fileder}'" - else + if '/' ~= fileder\sub 1, 1 assert origin, "cannot resolve relative path '#{fileder}' without origin!" + fileder = "#{origin.path}/#{fileder}" + + fileder = fileder\gsub '/([^/]-)/%.%./', '/' + if origin.path == fileder\sub 1, #origin.path assert (origin\walk fileder), "couldn't resolve path '#{fileder}' from #{origin}" + else + assert BROWSER and BROWSER.root, "cannot resolve absolute path '#{fileder}' without BROWSER and root set!" + assert (BROWSER.root\walk fileder), "couldn't resolve path '#{fileder}'" + + -- if 'string' == type fileder + -- if '/' == fileder\sub 1, 1 + -- fileder = fileder\gsub '/([^/]-)/%.%./', '/' + -- assert BROWSER and BROWSER.root, "cannot resolve absolute path '#{fileder}' without BROWSER and root set!" + -- assert (BROWSER.root\walk fileder), "couldn't resolve path '#{fileder}'" + -- else + -- assert origin, "cannot resolve relative path '#{fileder}' without origin!" + -- fileder = "#{origin.path}/#{fileder}" + -- fileder = fileder\gsub '/([^/]-)/%.%./', '/' + -- if origin.path == fileder\sub 1, #origin.path + -- assert (origin\walk fileder), "couldn't resolve path '#{fileder}' from #{origin}" + -- else + -- assert BROWSER and BROWSER.root, "cannot resolve absolute path '#{fileder}' without BROWSER and root set!" + -- assert (BROWSER.root\walk fileder), "couldn't resolve path '#{fileder}'" + else assert fileder, "no fileder passed." @@ -53,13 +73,18 @@ tourl = (path) -> ok, node = pcall fileder.gett, fileder, name, 'mmm/dom' if not ok - return span "couldn't embed #{fileder} #{name}", - (pre node), - class: 'embed' - style: { - background: 'var(--gray-fail)', - padding: '1em', - } + warn "couldn't embed #{fileder} #{name}: #{node}" + return span { + class: 'embed' + style: + background: 'var(--gray-fail)' + padding: '1em' + + "couldn't embed #{fileder} #{name}" + (pre node) + } + + return node if opts.raw klass = 'embed' klass ..= ' desc' if opts.desc diff --git a/root/articles/mmmfs/$order b/root/articles/mmmfs/$order index 81fb611..d8ac030 100644 --- a/root/articles/mmmfs/$order +++ b/root/articles/mmmfs/$order @@ -3,6 +3,6 @@ problem-statement framework mmmfs evaluation -references ba_log examples +references diff --git a/root/articles/mmmfs/references/$order b/root/articles/mmmfs/references/$order new file mode 100644 index 0000000..0360e6f --- /dev/null +++ b/root/articles/mmmfs/references/$order @@ -0,0 +1,2 @@ +xerox-star +unix diff --git a/root/articles/mmmfs/references/text$markdown.md b/root/articles/mmmfs/references/text$markdown.md deleted file mode 100644 index e69de29..0000000 diff --git a/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon new file mode 100644 index 0000000..7b86510 --- /dev/null +++ b/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon @@ -0,0 +1,6 @@ +=> + html = require 'mmm.dom' + import ol, li from html + + ol for ref in *@children + li ref\gett 'mmm/dom' diff --git a/root/articles/mmmfs/references/unix/URL -> cite$acm b/root/articles/mmmfs/references/unix/URL -> cite$acm new file mode 100644 index 0000000..b4a8d90 --- /dev/null +++ b/root/articles/mmmfs/references/unix/URL -> cite$acm @@ -0,0 +1 @@ +https://dl.acm.org/citation.cfm?id=577766 diff --git a/root/articles/mmmfs/references/xerox-star/URL -> cite$acm b/root/articles/mmmfs/references/xerox-star/URL -> cite$acm new file mode 100644 index 0000000..8b3d1a3 --- /dev/null +++ b/root/articles/mmmfs/references/xerox-star/URL -> cite$acm @@ -0,0 +1 @@ +https://dl.acm.org/citation.cfm?id=66894 diff --git a/scss/_content.scss b/scss/_content.scss index 51994a3..ad854de 100644 --- a/scss/_content.scss +++ b/scss/_content.scss @@ -7,6 +7,19 @@ .markdown { max-width: 640px; position: relative; + + &.wide { + max-width: max-content; + } + + > blockquote { + @include left-border; + + margin: 1rem var(--margin-wide); + padding: 1rem; + background: $gray-bright; + border-color: $gray-neutral; + } } .markdown, @@ -57,7 +70,6 @@ border-color: $gray-dark; display: block; - border-radius: 6px; margin: 0 var(--margin-wide); padding: 1em; white-space: pre-wrap; -- cgit v1.2.3 From 5bedc226eae70e557746428830f7b583f892a864 Mon Sep 17 00:00:00 2001 From: s-ol Date: Wed, 18 Dec 2019 16:27:51 +0100 Subject: protect print/deep_tostring from recursion --- mmm/init.client.moon | 10 +++++----- mmm/init.server.moon | 7 ++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/mmm/init.client.moon b/mmm/init.client.moon index 5fb3450..25c7da0 100644 --- a/mmm/init.client.moon +++ b/mmm/init.client.moon @@ -7,15 +7,15 @@ window = js.global MODE = 'CLIENT' UNSAFE = true -deep_tostring = (tbl, space='') -> - return tbl if 'userdata' == type tbl - +deep_tostring = (tbl, space='', recur={}) -> buf = space .. tostring tbl - return buf unless 'table' == (type tbl) and not tbl.__tostring + return buf unless 'table' == (type tbl) and not tbl.__tostring and not recur[tbl] + + recur[tbl] = true buf = buf .. ' {\n' for k,v in pairs tbl - buf = buf .. "#{space} [#{k}]: #{deep_tostring v, space .. ' '}\n" + buf = buf .. "#{space} [#{k}]: #{deep_tostring v, space .. ' ', recur}\n" buf = buf .. "#{space}}" buf diff --git a/mmm/init.server.moon b/mmm/init.server.moon index fbce18f..0e3534b 100644 --- a/mmm/init.server.moon +++ b/mmm/init.server.moon @@ -1,14 +1,15 @@ export MODE, print, warn, relative MODE = 'SERVER' -deep_tostring = (tbl, space='') -> +deep_tostring = (tbl, space='', recur={}) -> buf = space .. tostring tbl - return buf unless 'table' == (type tbl) and not tbl.__tostring + return buf unless 'table' == (type tbl) and not tbl.__tostring and not recur[tbl] + recur[tbl] = true buf = buf .. ' {\n' for k,v in pairs tbl - buf = buf .. "#{space} [#{k}]: #{deep_tostring v, space .. ' '}\n" + buf = buf .. "#{space} [#{k}]: #{deep_tostring v, space .. ' ', recur}\n" buf = buf .. "#{space}}" buf -- cgit v1.2.3 From a032d749b5819eeb7f9604dc352e8aef225c153c Mon Sep 17 00:00:00 2001 From: s-ol Date: Wed, 18 Dec 2019 16:28:50 +0100 Subject: fix server-side CORS HTTP requests --- mmm/mmmfs/plugins/cites.moon | 8 ++++++-- mmm/mmmfs/plugins/init.moon | 26 ++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/mmm/mmmfs/plugins/cites.moon b/mmm/mmmfs/plugins/cites.moon index 01f5b3f..b26241d 100644 --- a/mmm/mmmfs/plugins/cites.moon +++ b/mmm/mmmfs/plugins/cites.moon @@ -8,7 +8,11 @@ import div, i from require 'mmm.dom' cost: 0.5 transform: (url) => id = assert (url\match '//dl%.acm%.org/citation%.cfm%?id=(%d+)'), "couldn't parse cite/acm URL: '#{url}'" - "https://cors-anywhere.herokuapp.com/https://dl.acm.org/exportformats.cfm?id=#{id}&expformat=bibtex" + uri = "https://dl.acm.org/downformats.cfm?id=#{id}&parent_id=&expformat=bibtex" + if MODE == 'CLIENT' + "https://cors-anywhere.herokuapp.com/#{uri}" + else + uri } { inp: 'text/bibtex' @@ -20,7 +24,7 @@ import div, i from require 'mmm.dom' for key, val in kv\gmatch '([a-z]-)%s*=%s*{(.-)}' info[key] = val - div "#{info.author} (#{info.year}),", (i info.title), ". #{info.publisher}" + div "#{info.author} (#{info.year}), ", (i info.title), ". #{info.publisher}" } } } diff --git a/mmm/mmmfs/plugins/init.moon b/mmm/mmmfs/plugins/init.moon index 1650c3a..ba633a8 100644 --- a/mmm/mmmfs/plugins/init.moon +++ b/mmm/mmmfs/plugins/init.moon @@ -18,6 +18,23 @@ loadwith = (_load) -> (val, fileder, key) => func = assert _load val, "#{fileder}##{key}" func! +string.yieldable_gsub = (str, pat, f) -> + -- escape percent signs + str = str\gsub '%%', '%%|' + + matches = {} + str\gsub pat, (...) -> + table.insert matches, { ... } + "%#{#matches}" + + for match in *matches + match.replacement = f table.unpack match + + str\gsub '%%(%d+)', (i) -> matches[i].replacement + + -- unescape escaped percent signs + str\gsub '%%|', '%%' + -- list of converts, editors -- converts each have -- * inp - input type. can capture subtypes using `(.+)` @@ -59,7 +76,7 @@ converts = { cost: 0.1 transform: if MODE == 'SERVER' (html, fileder) => - html = html\gsub '(.-)', (attrs, text) -> + html = html\yieldable_gsub '(.-)', (attrs, text) -> text = nil if #text == 0 path = '' while attrs and attrs != '' @@ -76,7 +93,7 @@ converts = { link_to path, text, fileder - html = html\gsub '(.-)', (attrs, desc) -> + html = html\yieldable_gsub '(.-)', (attrs, desc) -> path, facet = '', '' opts = {} if #desc != 0 @@ -137,7 +154,7 @@ converts = { out: '%1', cost: 1 transform: (source, fileder) => - source\gsub '{{(.-)}}', (expr) -> + source\yieldable_gsub '{{(.-)}}', (expr) -> path, facet = expr\match '^([%w%-_%./]*)%+(.*)' assert path, "couldn't match TPL expression '#{expr}'" @@ -201,7 +218,8 @@ converts = { (uri) => request = require 'http.request' req = request.new_from_uri uri - headers, stream = req\go 8 + req.headers\upsert 'origin', 'null' + headers, stream = assert req\go 8 assert stream\get_body_as_string! } { -- cgit v1.2.3 From a1923464f33480eed90d69e4f54cf3c4b6274599 Mon Sep 17 00:00:00 2001 From: s-ol Date: Wed, 18 Dec 2019 17:29:29 +0100 Subject: more sidenote/reference formatting --- mmm/mmmfs/plugins/cites.moon | 21 +++++++++++++++++++-- root/articles/mmmfs/mmmfs/text$markdown.md | 6 ++++-- root/articles/mmmfs/references/$order | 1 + .../mmmfs/references/linux-exec/text$bibtex | 7 +++++++ scss/_sidenotes.scss | 1 + 5 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 root/articles/mmmfs/references/linux-exec/text$bibtex diff --git a/mmm/mmmfs/plugins/cites.moon b/mmm/mmmfs/plugins/cites.moon index b26241d..0223807 100644 --- a/mmm/mmmfs/plugins/cites.moon +++ b/mmm/mmmfs/plugins/cites.moon @@ -1,4 +1,12 @@ -import div, i from require 'mmm.dom' +import div, a, i, b from require 'mmm.dom' + +title = (info) -> + assert info.title, "cite doesn't have title" + inner = i info.title + if info.url + a inner, href: info.url + else + b inner { converts: { @@ -24,7 +32,16 @@ import div, i from require 'mmm.dom' for key, val in kv\gmatch '([a-z]-)%s*=%s*{(.-)}' info[key] = val - div "#{info.author} (#{info.year}), ", (i info.title), ". #{info.publisher}" + tt = title info + dot, com = if info.title\match '[.?!]$' then '', '' else '.', ',' + switch type + when 'book', 'article' + div "#{info.author} (#{info.year}), ", tt, "#{dot} #{info.publisher}" + when 'web' + -- note = if info.note then ", #{info.note}" else '' + div tt, "#{com} #{info.url} from #{info.visited}" + else + div "#{info.author} (#{info.year}), ", tt, "#{dot} #{info.publisher}" } } } diff --git a/root/articles/mmmfs/mmmfs/text$markdown.md b/root/articles/mmmfs/mmmfs/text$markdown.md index 214a720..c40b5db 100644 --- a/root/articles/mmmfs/mmmfs/text$markdown.md +++ b/root/articles/mmmfs/mmmfs/text$markdown.md @@ -18,14 +18,16 @@ Some metadata, such as file size and access permissions, is associated with each but notably the type of data is generally not actually stored in the filesystem, but determined loosely based on multiple heuristics depending on the system and context. Some notable mechanism are: + + - Suffixes in the name are often used to indicate what kind of data a file should contain. However there is no standardization over this, and often a suffix is used for multiple incompatible versions of a file-format. - Many file-formats specify a specific data-pattern either at the very beginning or very end of a given file. On unix systems the `libmagic` database and library of these so-called *magic constants* is commonly used to guess the file-type based on these fragments of data. -- on UNIX systems files to be executed are checked by a variety of methods to determine which format would fit. +-
+ on UNIX systems files to be executed are checked by a variety of methods to determine which format would fit. for script files, the "shebang" (`#!`) can be used to specify the program that should parse this file in the first line of the file. - [@TODO: src: https://stackoverflow.com/questions/23295724/how-does-linux-execute-a-file] It should be clear already from this short list that to mainstream operating systems, as well as the applications running on them, the format of a file is almost completely unknown and at best educated guesses can be made. diff --git a/root/articles/mmmfs/references/$order b/root/articles/mmmfs/references/$order index 0360e6f..59baea4 100644 --- a/root/articles/mmmfs/references/$order +++ b/root/articles/mmmfs/references/$order @@ -1,2 +1,3 @@ xerox-star unix +linux-exec diff --git a/root/articles/mmmfs/references/linux-exec/text$bibtex b/root/articles/mmmfs/references/linux-exec/text$bibtex new file mode 100644 index 0000000..6d52aa8 --- /dev/null +++ b/root/articles/mmmfs/references/linux-exec/text$bibtex @@ -0,0 +1,7 @@ +@web{23295968, + title = {How does Linux execute a file?}, + url = {https://stackoverflow.com/a/23295724/1598293}, + publisher = {stackoverflow.com}, + note = {answered by osgx}, + visited = {2019-12-18}, +} diff --git a/scss/_sidenotes.scss b/scss/_sidenotes.scss index 8579ba1..eddebc1 100644 --- a/scss/_sidenotes.scss +++ b/scss/_sidenotes.scss @@ -18,6 +18,7 @@ $sidenote-width: 14rem; color: $gray-dark; border-top: 1px solid $gray-dark; font-size: 0.8em; + word-break: break-word; @include media-medium { width: initial; -- cgit v1.2.3 From e5341f6ee4bceb1370acce7430d30c992433d08f Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 19 Dec 2019 20:47:10 +0100 Subject: lots of writing --- root/articles/mmmfs/$order | 4 +- root/articles/mmmfs/evaluation/text$markdown.md | 148 +++++++++++++++++---- .../mmmfs/examples/intro: text$markdown.md | 91 +++++++++++++ .../examples/pinwall/image/pinwall_info: text$json | 2 +- .../examples/pinwall/text/pinwall_info: text$json | 2 +- .../examples/pinwall/video/pinwall_info: text$json | 2 +- .../examples/text$moonscript -> fn -> mmm$dom.moon | 6 +- root/articles/mmmfs/framework/text$markdown.md | 94 ++++++++++++- root/articles/mmmfs/mmmfs/text$markdown.md | 44 +++--- .../mmmfs/problem-statement/text$markdown.md | 78 +++++++---- root/articles/mmmfs/references/$order | 6 + root/articles/mmmfs/references/acm-dl/text$bibtex | 4 + .../references/alternatives-to-trees/text$bibtex | 7 + .../mmmfs/references/aspect-ratios/text$bibtex | 7 + .../mmmfs/references/inkandswitch/text$bibtex | 7 + .../mmmfs/references/poc-or-gtfo/text$bibtex | 6 + .../mmmfs/references/subtext/URL -> cite$acm | 1 + .../mmmfs/text$moonscript -> fn -> mmm$dom.moon | 5 +- 18 files changed, 427 insertions(+), 87 deletions(-) create mode 100644 root/articles/mmmfs/examples/intro: text$markdown.md create mode 100644 root/articles/mmmfs/references/acm-dl/text$bibtex create mode 100644 root/articles/mmmfs/references/alternatives-to-trees/text$bibtex create mode 100644 root/articles/mmmfs/references/aspect-ratios/text$bibtex create mode 100644 root/articles/mmmfs/references/inkandswitch/text$bibtex create mode 100644 root/articles/mmmfs/references/poc-or-gtfo/text$bibtex create mode 100644 root/articles/mmmfs/references/subtext/URL -> cite$acm diff --git a/root/articles/mmmfs/$order b/root/articles/mmmfs/$order index d8ac030..6707527 100644 --- a/root/articles/mmmfs/$order +++ b/root/articles/mmmfs/$order @@ -2,7 +2,7 @@ abstract problem-statement framework mmmfs -evaluation -ba_log examples +evaluation references +ba_log diff --git a/root/articles/mmmfs/evaluation/text$markdown.md b/root/articles/mmmfs/evaluation/text$markdown.md index 87404cd..773c842 100644 --- a/root/articles/mmmfs/evaluation/text$markdown.md +++ b/root/articles/mmmfs/evaluation/text$markdown.md @@ -1,7 +1,75 @@ -Drawbacks & Future Work ------------------------ +evaluation +========== -There are multiple limitations in the proposed system that have become obvious in developing and working with the system. +## examples +### publishing and blogging +Since mmmfs has grown out of the need for a versatile CMS for a personal publishing website, it is not surprising to +to see that it is still up to that job. Nevertheless it is worth taking a look at its strengths and weaknesses in this +context: + +The system has proven itself perfect for publishing small- and medium-size articles and blog posts, especially for its +ability to flexibly transclude content from any source. This includes diagrams (such as in this thesis), +videos (as in the documentation in the appendix), but also less conventional media such as +interactive diagrams or twitter postings. + +On the other hand, the development of the technical framework for this very thesis has posed greater challenges. +In particular, the implementation of the reference and sidenote systems are brittle and uninspiring. + +This is mostly due to the approach of splitting up the thesis into a multitude of fileders, and the current lack of +mechanisms to re-capture information spread throughout the resulting history effectively. +Another issue is that the system is currently based on the presumption that content can and should be interpreted +separate from its parent and context in most cases. This has made the implementation of sidenotes less idiomatic +than initially anticipated. + +### pinwall +The pinwall example shows some strenghts of the mmmfs system pretty convincingly. +The type coercion layer completely abstracts away the complexities of transcluding different types of content, +and only positioning and sizing the content, as well as enabling interaction, remain to handle in the pinwall fileder. + +A great benefit of the use of mmmfs versus other technology for realising this example is that the example can +seamlessly embed not only plain text, markdown, images, videos, and interactive widgets, but also follow links to all +of these types of content, and display them meaningfully. Accomplishing this with traditional frameworks would take +great effort, where mmmfs benefits from the reuse of these conversions across the whole system. + +In addition, the script for the pinwall folder is 120 lines long, of which 30 lines are styling, while almost 60 lines +take care of capturing and handling JS events. The bulk of complexity is therefore shifted towards interacting with the +UI layer (in this case the browser), which could feasibly be simplified through a custom abstraction layer or the use of +output means other than the web. + +### slideshow +A simplified image slideshow example consists of only 20 lines of code and demonstrates how the reactive component +framework simplifies the generation of ad-hoc UI dramatically: + +```moon +import ReactiveVar, text, elements from require 'mmm.component' +import div, a, img from elements + +=> + index = ReactiveVar 1 + + prev = (i) -> math.max 1, i - 1 + next = (i) -> math.min #@children, i + 1 + + div { + div { + a 'prev', href: '#', onclick: -> index\transform prev + index\map (i) -> text " image ##{i} " + a 'next', href: '#', onclick: -> index\transform next + }, + index\map (i) -> + child = assert @children[i], "image not found!" + img src: @children[i]\gett 'URL -> image/png' + } +``` + +The presentation framework is a bit longer, but the added complexity is again required to deal with browser quirks, +such as the fullscreen API and sizing content proportionally to the viewport size. +The parts of the code dealing with the content are essentially identical, except that content is transcluded via the +more general `mmm/dom` type-interface, allowing for a greater variety of types of content to be used as slides. + +## general concerns +While the system has proven pretty successfuly and moldable to the different use-cases that it has been tested in, +there are also limitations in the proposed system that have become obvious in developing and working with the system. Some of these have been anticipated for some time and concrete research directions for solutions are apparent, while others may be intrinsic limitations in the approach taken. @@ -12,7 +80,7 @@ Therefore it is necessary to encode behaviour directly (as code) in facets where For example if a fileder conatining multiple images wants to provide custom UI for each image when viewed independently, this code has to either be attached to every image individually (and redundantly), or added as a global convert. To make sure this convert does not interfere with images elsewhere in the system, it would be necessary to introduce -a new type and change the images to use it, which may present yet more propblems and works against the principle of +a new type and change the images to use it, which may present more problems yet and works against the principle of compatibility the system has been constructed for. A potential direction of research in the future is to allow specifying *converts* as part of the fileder tree. @@ -22,45 +90,62 @@ This way, *converts* can be added locally if they only make sense within a given Additionally it could be made possible to use this mechanism to locally override *converts* inherited from further up in the tree, for example to specialize types based on their context in the system. +The biggest downside to this approach would be that it presents another pressure factor for, +while also reincforcing, the hierarchical organization of data, +thereby exacerbating the limits of hierarchical structures.
see also +
+ ### code outside of the system -At the moment, a large part of the mmmfs codebase is still separate from the content, and developed outside of mmmfs itself. -This is a result of the development process of mmmfs and was necessary to start the project as the filesystem itself matured, -but has become a limitation of the user experience now: -Potential users of mmmfs would generally start by becoming familiar with the operation of mmmfs from within the system, -as this is the expected (and designated) experience developed for them. -All of the code that lives outside of the mmmfs tree is therefore invisible and opaque to them, -actively limiting their understanding of, and the customizability of the system. - -This is particularily relevant for the global set of *converts*, and the layout used to render the web view, -which are expected to undergo changes as users adapt the system to their own content types and domains of interest, -as well as their visual identity, respectively. - -### superficial type system +At the moment, a large part of the mmmfs codebase is still separate from the content, and developed outside of mmmfs +itself. This is a result of the development process of mmmfs and was necessary to start the project as the filesystem +itself matured, but has become a limitation of the user experience now: Potential users of mmmfs would generally start +by becoming familiar with the operation of mmmfs from within the system, as this is the expected (and designated) +experience developed for them. All of the code that lives outside of the mmmfs tree is therefore invisible and opaque +to them, actively limiting their understanding, and thereby the customizability, of the system. + +This weakness represents a failure to (fully) implement the quality of a "Living System" as proposed by +*Ink and Switch*. + +In general however, some portion of code may always have to be left outside of the system. +This also wouldn't necessarily represent a problem, but in this case it is particularily relevant +for the global set of *converts* (see above), as well as the layout used to render the web view, +both of which are expected to undergo changes as users adapt the system to their own content types and +domains of interest, as well as their visual identity, respectively. + +### type system The currently used type system based on strings and pattern matching has been largely satisfactory, -but has proven problematic for satisfying some anticipated use cases. -It should be considered to switch to a more intricate, structural type system that allows encoding more concrete meta-data -alongside the type, and to match *converts* based on a more flexible scheme of pattern matching. +but has proven problematic for some anticipated use cases. +It should be considered to switch to a more intricate, +structural type system that allows encoding more concrete meta-data alongside the type, +and to match *converts* based on a more flexible scheme of pattern matching. For example it is envisaged to store the resolution of an image file in its type. Many *converts* might choose to ignore this additional information, but others could use this information to generate lower-resolution 'thumbnails' of images automatically. Using these mechanisms for example images could be requested with a maximum-resolution constraint to save on bandwidth when embedded in other documents. -### type-coercion alienates +### type-coercion By giving the system more information about the data it is dealing with, and then relying on the system to automatically transform between data-types, it is easy to lose track of which format data is concretely stored in. In much the same way that the application-centric paradigm alienates users from an understanding and feeling of ownership of their data by overemphasizing the tools in between, -the automagical coercion of data types introduces distance between the user and an understanding of the data in the system. -It remains to be seen whether this can be mitigated with careful UX and UI design. +the automagical coercion of data types introduces distance between the user and +an understanding of the data in the system. +This poses a threat to the transparency of the system, and a potential lack of the quality of "Embodiment" (see above). + +Potential solutions could be to communicate the conversion path clearly and explicitly together with the content, +as well as making this display interactive to encourage experimentation with custom conversion queries. +Emphasising the conversion process more strongly in this way might be able to turn this feature from an opaque +hindrance into a transparent tool using careful UX and UI design. -### discrepancy between viewing/interacting and editing of content +### editing Because many *converts* are not necessarily reversible, it is very hard to implement generic ways of editing stored data in the same format it is viewed. For example, the system trivially converts markdown-formatted text sources into viewable HTML markup, but it is hardly possible to propagate changes to the viewable HTML back to the markdown source. -This problem worsens when the conversion path becomes more complex: +This particular instance of the problem might be solvable using a Rich-Text editor, but the general problem +worsens when the conversion path becomes more complex: If the markdown source was fetched via HTTP from a remote URL (e.g. if the facet's type was `URL -> text/markdown`), it is not possible to edit the content at all, since the only data owned by the system is the URL string itself, which is not part of the viewable representation at all. @@ -68,7 +153,14 @@ Similarily, when viewing output that is generated by code (e.g. `text/moonscript the code itself is not visible to the user when interacting with the viewable representation, and if the user wishes to change parts of the representation the system is unable to relate these changes to elements of the code or assist the user in doing so. + +However even where plain text is used and edited, a shortcoming of the current approach to editing is evident: +The content editor is wholly separate from the visible representation, and only facets of the currently viewed +fileder can be edited. This means that content cannot be edited in its context, which is particularily annoying +due to the fragmentation of content that mmmfs encourages. + As a result, the experiences of interacting with the system at large is still a very different experience than -editing content (and thereby extending the system) in it. -This is expected to represent a major hurdle for users getting started with the system, -and is a major shortcoming in enabling end-user programming as set as a goal for this project. +editing content (and thereby extending the system) in it. This is expected to represent a major hurdle for users +getting started with the system, and is a major shortcoming in enabling end-user programming as set as a goal for +this project. A future iteration should take care to reconsider how editing can be integrated more holistically +with the other core concepts of the design. diff --git a/root/articles/mmmfs/examples/intro: text$markdown.md b/root/articles/mmmfs/examples/intro: text$markdown.md new file mode 100644 index 0000000..a427ae8 --- /dev/null +++ b/root/articles/mmmfs/examples/intro: text$markdown.md @@ -0,0 +1,91 @@ +# examples +To illustrate the capabilities of the proposed system, and to compare the results with the framework introduced above, +a number of example use cases have been chosen and implemented from the perspective of a user. +In the following section I will introduce these use cases and briefly summarize the implementation +approach in terms of the capabilities of the proposed system. + +## publishing and blogging +### blogging +Blogging is pretty straightforward, since it generally just involves publishing lightly-formatted text, +interspersed with media such as images and videos or perhaps social media posts. +Markdown is a great tool for this job, and has been integrated in the system to much success: +There are two different types registered with *converts*: `text/markdown` and `text/markdown+span`. +They both render to HTML (and DOM nodes), so they are immediately viewable as part of the system. +The only difference for `text/markdown+span` is that it is limited to a single line, +and doesn't render as a paragraph but rather just a line of text. +This makes it suitable for denoting formatted-text titles and other small strings of text. + +The problem of embedding other content together with text comfortably is also solved easily, +becase Markdown allows embedding arbitrary HTML in the document. +This made it possible to define a set of pseudo-HTML elements in the Markdown-convert, +`` and ``, which respectively embed and link to other content native to mmm. + +### scientific publishing +
+One of the 'standard' solutions, LaTeX, +is arguably at least as complex as the mmm system proposed here, but has a much narrower scope, +since it does not support interaction. +
+Scientific publishing is notoriously complex, involving not only the transclusion of diagrams +and other media, but generally requiring precise and consistent control over formatting and layout. +Some of these complexities are tedious to manage, but present good opportunities for programmatic +systems and media to do work for the writer. + +One such topic is the topic of references. +References appear in various formats at multiple positions in a scientific document; +usually they are referenced via a reduced visual form within the text of the document, +and then shown again with full details at the end of the document. + +For the sake of this thesis, referencing has been implemented using a subset of the popular +BibTeX format for describing citations. Converts have been implemented for the `text/bibtex` +type to convert to a full reference format (to `mmm/dom`) and to an inline side-note reference +(`mmm/dom+link`) that can be transcluded using the `` pseudo-tag. + +For convenience, a convert from the `URL -> cite/acm` type has been provided to `URL -> text/bibtex`, +which generates links to the ACM Digital Library +API for accessing BibTeX citations for documents in the library. +This means that it is enough to store the link to the ACM DL entry in mmmfs, +and the reference will automatically be fetched (and track potential remote corrections). + +## pinwall +In many situations, in particular for creative work, it is often useful to compile resources of +different types for reference or inspiration, and arrange them spacially so that they can be viewed +at a glance or organized into different contexts etc. +Such a pinwall could serve for example to organise references to articles, +to collect visual inspiration for a moodboard etc. + +As a collection, the Pinwall is primarily mapped to a Fileder in the system. +Any content that is placed within can then be rendered by the Pinwall, +which can constrain every piece of content to a rectangular piece on its canvas. +This is possible through a simple script, e.g. of the type `text/moonscript -> fn -> mmm/dom`, +which enumerates the list of children, wraps each in such a rectangular container, +and outputs the list of containers as DOM elements. + +The position and size of each panel are stored in an ad-hoc facet, encoded in the JSON data format: +`pinwall_info: text/json`. This facet can then set on each child and accessed whenever the script is called +to render the children, plugging the values within the facet into the visual styling of the document. + +The script can also set event handlers that react to user input while the document is loaded, +and allow the user to reposition and resize the individual pinwall items by clicking and dragging +on the upper border or lower right-hand corner respectively. +Whenever a change is made the event handler can then update the value in the `pinwall_info` facet, +so that the script places the content at the updated position and size next time it is invoked. + +## slideshow +Another common use of digital documents is as aids in a verbal presentation. +These often take the form of slideshows, for the creation of which a number of established applications exist. +In simple terms, a slideshow is simply a linear series of screen-sized documents, that can be +advanced (and rewound) one by one using keypresses. + +The implementation of this is rather straightforward as well. +The slideshow as a whole becomes a fileder with a script that generates a designated viewport rectangle, +as well as a control interface with keys for advancing the active slide. +It also allows putting the browser into fullscreen mode to maximise screenspace and remove visual elements +of the website that may distract from the presentation, and register an event handler for keyboard accelerators +for moving through the presentation. + +Finally the script simply embeds the first of its child-fileders into the viewport rect. +One the current slide is changed, the next embedded child is simply chosen. + +## code documentation +/meta/mmm.dom/:%20text/html+interactive diff --git a/root/articles/mmmfs/examples/pinwall/image/pinwall_info: text$json b/root/articles/mmmfs/examples/pinwall/image/pinwall_info: text$json index 74fba2c..e5893ac 100644 --- a/root/articles/mmmfs/examples/pinwall/image/pinwall_info: text$json +++ b/root/articles/mmmfs/examples/pinwall/image/pinwall_info: text$json @@ -1 +1 @@ -{"x": 35.0, "y": 209.0, "w": 205.0, "h": 155.0} \ No newline at end of file +{"x": 94.0, "y": 265.0, "w": 205.0, "h": 155.0} \ No newline at end of file diff --git a/root/articles/mmmfs/examples/pinwall/text/pinwall_info: text$json b/root/articles/mmmfs/examples/pinwall/text/pinwall_info: text$json index d373545..39bdb45 100644 --- a/root/articles/mmmfs/examples/pinwall/text/pinwall_info: text$json +++ b/root/articles/mmmfs/examples/pinwall/text/pinwall_info: text$json @@ -1 +1 @@ -{"x": 91.0, "y": 17.0, "w": 186.0, "h": 128.0} \ No newline at end of file +{"x": 53.0, "y": 64.0, "w": 396.0, "h": 74.0} \ No newline at end of file diff --git a/root/articles/mmmfs/examples/pinwall/video/pinwall_info: text$json b/root/articles/mmmfs/examples/pinwall/video/pinwall_info: text$json index 30c947e..7be8702 100644 --- a/root/articles/mmmfs/examples/pinwall/video/pinwall_info: text$json +++ b/root/articles/mmmfs/examples/pinwall/video/pinwall_info: text$json @@ -1 +1 @@ -{"x": 263.0, "y": 210.0, "w": 353.0, "h": 295.0} \ No newline at end of file +{"x": 534.0, "y": 136.0, "w": 387.0, "h": 218.0} \ No newline at end of file diff --git a/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon index ca9078c..a553f8d 100644 --- a/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon @@ -28,5 +28,9 @@ }, } - div for child in *@children + content = for child in *@children preview child + + table.insert content, 1, (@gett 'intro: mmm/dom') + + div content diff --git a/root/articles/mmmfs/framework/text$markdown.md b/root/articles/mmmfs/framework/text$markdown.md index cc059ad..af446a5 100644 --- a/root/articles/mmmfs/framework/text$markdown.md +++ b/root/articles/mmmfs/framework/text$markdown.md @@ -1,3 +1,68 @@ +Two of the earliest wholistic computing systems, the Xerox Alto and Xerox Star, both developed at Xerox PARC and introduced in the 70s and early 80s, pioneered not only graphical user-interfaces, but also the "Desktop Metaphor". +The desktop metaphor presents information as stored in "Documents" that can be organized in folders and on the "Desktop". It invokes a strong analogy to physical tools. +One of the differences between the Xerox Star system and other systems at the time, as well as the systems we use currently, is that the type of data a file represents is directly known to the system. + +
+ +> In a Desktop metaphor system, users deal mainly with data files, oblivious to the existence of programs. +> They do not "invoke a text editor", they "open a document". +> The system knows the type of each file and notifies the relevant application program when one is opened. +> +> The disadvantage of assigning data files to applications is that users sometimes want to operate on a file with a program other than +its "assigned" application. \[...\] +> Star's designers feel that, for its audience, the advantages of allowing users to forget +about programs outweighs this disadvantage. + +Other systems at the time lacked any knowledge of the type of files, +and while mainstream operating systems of today have retro-fit the ability to associate and memorize the preferred applications to use for a given file based on it's name suffix, the intention of making applications a secondary, technical detail of working with the computer has surely been lost. + +Another design detail of the Star system is the concept of "properties" that are stored for "objects" throughout the system (the objects being anything from files to characters or paragraphs). +These typed pieces of information are labelled with a name and persistently stored, providing a mechanism to store metadata such as user preference for ordering or defaut view of a folder for example. + +*** + +Fig. 8 - Star Retrospective + +The earliest indirect influence for the Xerox Alto and many other systems of its time, +was the *Memex*. The *Memex* is a hypothetical device and system for knowledge management. +Proposed by Vannevar Bush in 1945, the concept predates much of the technology that later was used to implement many parts of the vision. In essence, the concept of hypertext was invented. + +*** + +One of the systems that could be said to have come closest to a practical implementation of the Memex might be Apple's *Hypercard*. + +https://archive.org/details/CC501_hypercard + +"So I can have the information in these stacks tied together in a way that makes sense" + +In a demonstration video, the creators of the software showcase a system of stacks of cards that together implement, amongst others, a calendar (with yearly and weekly views), a list of digital business cards for storing phone numbers and addresses, and a todo list. +However these stacks of cards are not just usable by themselves, it is also demonstrated how stacks can link to each other in meaningful ways, such as jumping to the card corresponding to a specific day from the yearly calendar view, or automatically looking up the card corresponding to a person's first name from a mention of the name in the text on a different card. + +Alongside Spreadsheets, *Hypercard* remains one of the most successful implementations of end-user programming, even today. +While it's technical abilities have been long matched and passed by other software (such as the ubiquitous HTML hypertext markup language), these technical successors have failed the legacy of *Hypercard* as an end-user tool: +while it is easier than ever to publish content on the web (through various social media and microblogging services), the benefits of hypermedia as a customizable medium for personal management have nearly vanished. +End-users do not create hypertext anymore. + +The *UNIX Philosophy* +describes the software design paradigm pioneered in the creation of the Unix operating system at the AT&T Bell Labs +research center in the 1960s. The concepts are considered quite influental and are still notably applied in the Linux community. +Many attempts at summaries exist, but the following includes the pieces that are especially relevant even today: + +> Even though the UNIX system introduces a number of innovative programs and techniques, no single program or idea makes it work well. +> Instead, what makes it effective is the approach to programming, a philosophy of using the computer. Although that philosophy can't be +> written down in a single sentence, at its heart is the idea that the power of a system comes more from the relationships among programs +> than from the programs themselves. Many UNIX programs do quite trivial things in isolation, but, combined with other programs, +> become general and useful tools. + +This approach has multiple benefits with regard to end-user programmability: +Assembling the system out of simple, modular pieces means that for any given task a user may want to implement, +it is very likely that preexisting parts of the system can help the user realize a solution. +Wherever such a preexisting part exists, it pays off designing it in such a way that it is easy to integrate for the user later. +Assembling the system as a collection of modular, interacting pieces also enables future growth and customization, +since pieces may be swapped out with customized or alternate software at any time. + +*** + Based on this, a modern data storage and processing ecosystem should enable transclusion of both content and behaviours between contexts. Content should be able to be transcluded and referenced to facilitate the creation of flexible data formats and interactions, @@ -9,7 +74,32 @@ The system should enable the quick creation of ad-hoc software. While there are drawbacks to cloud-storage of data (as outlined above), the utility of distributed systems is acknowledged, and the system should therefore be able to include content and behaviours via the network. -This ability should be integrated deeply into the system, so that data can be treated independently of its origin and storage conditions, -with as little caveats as possible. +This ability should be integrated deeply into the system, +so that data can be treated independently of its origin and storage conditions, with as little caveats as possible. The system needs to be browsable and understandable by users. + +In order to provide users full access to their information as well as the computational infrastructure, +users need to be able to finely customize and reorganize the smallest pieces to suit their own purposes, +in other words: be able to program. + +While there is an ongoing area of research focusing on the development of new programming paradigms, +methodologies and tools that are more accessible and cater to the wide +range of end-users, +in order to keep the scope of this work appropriate, +conventional programming languages are used for the time being. +Confidence is placed in the fact that eventually more user-friendly languages will be available and, +given the goal of modularity, should be implementable in a straightforward fashion. + +*Ink and Switch* suggest three qualities for tools striving to support +end-user programming: + +- "Embodiment", i.e. reifying central concepts of the programming model as more concrete, tangible objects + in the digital space (for example through visual representation), + in order to reduce cognitive load on the user. +- "Living System", by which they seem to describe the malleability of a system or environment, + and in particular the ability to make changes at different levels of depth in the system with + very short feedback loops and a feeling of direct experience. +- "In-place toolchain", denoting the availability of tools to customize and author the experience, + as well as a certain accesibility of these tools, granted by a conceptual affinity between the + use of the tools and general 'passive' use of containing system at large. diff --git a/root/articles/mmmfs/mmmfs/text$markdown.md b/root/articles/mmmfs/mmmfs/text$markdown.md index c40b5db..7a682dd 100644 --- a/root/articles/mmmfs/mmmfs/text$markdown.md +++ b/root/articles/mmmfs/mmmfs/text$markdown.md @@ -1,9 +1,10 @@ +# mmmfs `mmmfs` seeks to improve on two fronts. One of the main driving ideas of the mmmfs is to help data portability and use by making it simpler to inter-operate with different data formats. This is accomplished using two major components, the *Type System and Coercion Engine* and the *Fileder Unified Data Model* for unified data storage and access. -# The Fileder Unified Data Model +## the fileder unified data model The Fileder Model is the underlying unified data storage model. Like many data storage models it is based fundamentally on the concept of a hierarchical tree-structure. @@ -20,31 +21,30 @@ but determined loosely based on multiple heuristics depending on the system and Some notable mechanism are: -- Suffixes in the name are often used to indicate what kind of data a file should contain. - However there is no standardization over this, and often a suffix is used for multiple incompatible versions of a file-format. +- Suffixes in the name are often used to indicate what kind of data a file should contain. However there is no standardization +- over this, and often a suffix is used for multiple incompatible versions of a file-format. - Many file-formats specify a specific data-pattern either at the very beginning or very end of a given file. - On unix systems the `libmagic` database and library of these so-called *magic constants* is commonly used to guess the file-type based on - these fragments of data. --
- on UNIX systems files to be executed are checked by a variety of methods to determine which format would fit. - for script files, the "shebang" (`#!`) can be used to specify the program that should parse this file in the first line of the file. + On unix systems the `libmagic` database and library of these so-called *magic constants* is commonly used to guess + the file-type based on these fragments of data. +- on UNIX systems, files to be executed are checked by a variety of methods + in order to determine which format would fit. For example, script files, the "shebang" symbol, `#!`, can + be used to specify the program that should parse this file in the first line of the file. -It should be clear already from this short list that to mainstream operating systems, as well as the applications running on them, -the format of a file is almost completely unknown and at best educated guesses can be made. +It should be clear already from this short list that to mainstream operating systems, as well as the applications +running on them, the format of a file is almost completely unknown and at best educated guesses can be made. Because these various mechanisms are applied at different times by the operating system and applications, it is possible for files to be labelled as or considered as being in different formats at the same time by different components of the system. -This leads to confusion about the factual format of data among users (e.g. making unclear the difference between changing a file extension -and converting a file between formats [TODO: quote below]), but can also pose a serious security risk. -It is for example possible, under some circumstances, -that a file contains maliciously-crafted code and is treated as an executable by one software component, -while a security mechanism meant to detect such code determines the same file to be a legitimate image -(the file may in fact be valid in both formats). -[TODO: quote: "Abusing file formats; or, Corkami, the Novella", Ange Albertini, PoC||GTFO 7] - -Users renaming extensions: - https://askubuntu.com/questions/166602/why-is-it-possible-to-convert-a-file-just-by-renaming-its-extension - https://www.quora.com/What-happens-when-you-rename-a-jpg-to-a-png-file +
+The difference between changing a file extension and converting a file between two formats is commonly unclear to users, +for example: see +Why is it possible to convert a file just by renaming it?, https://askubuntu.com/q/166602 + from 2019-12-18 +
+This leads to confusion about the factual format of data among users, but can also pose a serious security risk: +Under some circumstances it is possible that a file contains maliciously-crafted code and is treated as an executable +by one software component, while a security mechanism meant to detect such code determines the same file to be a +legitimate image (the file may in fact be valid in both formats). In mmmfs, the example above might look like this instead: schematic view of an example mmmfs tree @@ -69,7 +69,7 @@ Semantically a *fileder*, like a *directory*, also encompasses all the other *fi Since *fileders* are the primary unit of data to be operated upon, *fileder* nesting emerges as a natural way of structuring complex data, both for access by the system and applications, as well as the user themself. -# The Type System & Coercion Engine +## the type system & coercion engine As mentioned above, *facets* store data alongside its *type*, and when applications require data from a *fileder*, they specify the *type* (or the list of *types*) that they require the type to be in. diff --git a/root/articles/mmmfs/problem-statement/text$markdown.md b/root/articles/mmmfs/problem-statement/text$markdown.md index 78dbd76..4723f01 100644 --- a/root/articles/mmmfs/problem-statement/text$markdown.md +++ b/root/articles/mmmfs/problem-statement/text$markdown.md @@ -1,28 +1,33 @@ # motivation -The application-centric computing paradigm common today is harmful to users, -because it leaves behind "intert" data as D. Cragg calls it: -[Cragg 2016] -D. Cragg coins the term "inert data" for the data created, and left behind, by apps and applications in the computing model that is currently prevalent: -Most data today is either intrinsically linked to one specific application, that controls and limits access to the actual information, -or even worse, stored in the cloud where users have no direct access at all and depend soley on online tools that require a stable network connection -and a modern browser, and that could be modified, removed or otherwise negatively impacted at any moment. +The majority of users interacts with modern computing systems in the form of smartphones, laptops or desktop PCs, +using the mainstream operating systems Apple iOS and Mac OS X, Microsoft Windows or Android. -This issue is worsened by the fact that the a lot of software we use today is deployed through the cloud computing and SaaS paradigms, -which are far less reliable than earlier means of distributing software: -Software that runs in the cloud is subject to outages due to network problems, -pricing or availability changes etc. at the whim of the company providing it, as well as ISPs involved in the distribution. -Cloud software, as well as subscription-model software with online-verification mechanisms are additionally subject -to license changes, updates modifiying, restricting or simply removing past functionality etc. -Additionally, many cloud software solutions and ecosystems store the users' data in the cloud, -where they are subject to foreign laws and privacy concerns are intransparently handled by the companies. -Should the company, for any reason, be unable or unwanting to continue servicing a customer, -the data may be irrecoverably lost (or access prevented). +All of these operating systems share the concept of *Applications* (or *Apps*) as one of the core pieces of their interaction model. +Functionality and capabilities of the digital devices are bundled in, marketed, sold and distributed as *Applications*. + +In addition, a lot of functionality is nowadays delivered in the form of *Web Apps*, which are used inside a *Browser* (which is an *Application* itself). +*Web Apps* often offer similar functionality to other *Applications*, but are subject to some limitations: +In most cases, they are only accessible or functional in the presence of a stable internet connection, +and they have very limited access to the resources of the physical computer they are running on. +For example, they usually cannot interact directly with the file system, hardware peripherals or other applications, +other than through a standardized set of interactions (e.g. selecting a file via a visual menu, capturing audio and video from a webcam, opening another website). + +On the two Desktop Operating Systems (Mac OS X and Windows), file management and the concepts of *Documents* are still central +elements of interactions with the system. The two prevalent smartphone systems deemphasize this concept by only allowing access to the +data actually stored on the device through an app itself. + +This focus on *Applications* as the primary unit of systems can be seen as the root cause of multiple problems: +Because applications are the products companies produce, and software represents a market of users, +developers compete on features integrated into their applications. However this lack of control over data access is not the only problem the application-centric approach induces: -Another consequence is that interoperability between applications and data formats is hindered. -Because applications are incentivised to keep customers, they make use of network effects to keep customers locked-in. +A consequence of this is that interoperability between applications and data formats is rare. +To stay relevant, monlithic software or software suites are designed to As a result applications tend to accrete features rather then modularise and delegate to other software [P Chiusano]. +Because applications are incentivised to keep customers, they make use of network effects to keep customers locked-in. +This often means re-implementing services and functinality that is already available +and integrating it directly in other applications produced by the same organisation. This leads to massively complex file formats, such as for example the .docx format commonly used for storing mostly @@ -40,9 +45,28 @@ If the word-processing application supports this, the old image may be replaced directly, otherwise the user may have to remove the old image, insert the new one and carefully ensure that the positioning in the document remains intact. -In fact all of this is unnecessary, since the image had been stored in a compatible format on disk in the first place: -The system was simply unaware of this because the word document had to be archived into a single file -for ease of use by the word processor, and this single file is opaque to the system. +https://www.theverge.com/2019/10/7/20904030/adobe-venezuela-photoshop-behance-us-sanctions + + +The application-centric computing paradigm common today is harmful to users, +because it leaves behind "intert" data as D. Cragg calls it: + +[Cragg 2016] +D. Cragg coins the term "inert data" for the data created, and left behind, by apps and applications in the computing model that is currently prevalent: +Most data today is either intrinsically linked to one specific application, that controls and limits access to the actual information, +or even worse, stored in the cloud where users have no direct access at all and depend soley on online tools that require a stable network connection +and a modern browser, and that could be modified, removed or otherwise negatively impacted at any moment. + +This issue is worsened by the fact that the a lot of software we use today is deployed through the cloud computing and SaaS paradigms, +which are far less reliable than earlier means of distributing software: +Software that runs in the cloud is subject to outages due to network problems, +pricing or availability changes etc. at the whim of the company providing it, as well as ISPs involved in the distribution. +Cloud software, as well as subscription-model software with online-verification mechanisms are additionally subject +to license changes, updates modifiying, restricting or simply removing past functionality etc. +Additionally, many cloud software solutions and ecosystems store the users' data in the cloud, +where they are subject to foreign laws and privacy concerns are intransparently handled by the companies. +Should the company, for any reason, be unable or unwanting to continue servicing a customer, +the data may be irrecoverably lost (or access prevented). Data rarely really fits the metaphora of files very well, and even when it does it is rarely exposed to the user that way: @@ -69,10 +93,7 @@ composable pieces of software that naturally lend themselves to, or outrightly c integration into the users' other systems and customization, rather than lure into the walled-gardens of corporate ecosystems using network-effects. -Services like this are - -not even directly accessible to end-users anymore -Data is inert ko[Cragg 2016] +Data is inert [Cragg 2016] Key points: - data ownership @@ -100,3 +121,8 @@ word documents are capable of containing texts and images, but when the files ar contained data is lost. It is for example a non-trivial and unenjoyable task to edit an image file contained in a word document in another application and have the changes apply to the document. In the same way, text contained in a photoshop document cannot be edited in a text editor of your choice. + +Creative use of computer technology is limited to programmers, since applications constrain their users to the +paths and abilities that the developers anticipated and deemed useful. +Note that 'creative' here does not only encompass 'artistic': this applies to any field and means +that innovative use of technology is unlikely to happen as a result of practice by domain experts. diff --git a/root/articles/mmmfs/references/$order b/root/articles/mmmfs/references/$order index 59baea4..2388177 100644 --- a/root/articles/mmmfs/references/$order +++ b/root/articles/mmmfs/references/$order @@ -1,3 +1,9 @@ xerox-star unix +subtext +inkandswitch linux-exec +poc-or-gtfo +acm-dl +aspect-ratios +alternatives-to-trees diff --git a/root/articles/mmmfs/references/acm-dl/text$bibtex b/root/articles/mmmfs/references/acm-dl/text$bibtex new file mode 100644 index 0000000..97b053f --- /dev/null +++ b/root/articles/mmmfs/references/acm-dl/text$bibtex @@ -0,0 +1,4 @@ +@web{acm-dl, + title = {ACM Digital Library}, + url = {https://dl.acm.org}, +} diff --git a/root/articles/mmmfs/references/alternatives-to-trees/text$bibtex b/root/articles/mmmfs/references/alternatives-to-trees/text$bibtex new file mode 100644 index 0000000..19c134e --- /dev/null +++ b/root/articles/mmmfs/references/alternatives-to-trees/text$bibtex @@ -0,0 +1,7 @@ +@web{alternatives:to:trees, + title = {Alternatives to Trees}, + url = {https://www.oocities.org/tablizer/sets1.htm}, + author = {Jacobs, B.} + year = {2004}, + visited = {2019-12-18}, +} diff --git a/root/articles/mmmfs/references/aspect-ratios/text$bibtex b/root/articles/mmmfs/references/aspect-ratios/text$bibtex new file mode 100644 index 0000000..6536419 --- /dev/null +++ b/root/articles/mmmfs/references/aspect-ratios/text$bibtex @@ -0,0 +1,7 @@ +@web{aspect:ratios, + title = {Aspect-ratio independent UIs}, + url = {https://s-ol.nu/aspect-ratios}, + author = {Bekic, S.} + year = {2019}, + visited = {2019-12-18}, +} diff --git a/root/articles/mmmfs/references/inkandswitch/text$bibtex b/root/articles/mmmfs/references/inkandswitch/text$bibtex new file mode 100644 index 0000000..48fe03c --- /dev/null +++ b/root/articles/mmmfs/references/inkandswitch/text$bibtex @@ -0,0 +1,7 @@ +@web{inkandswitch, + title = {End-user Programming}, + url = {https://inkandswitch.com/end-user-programming.html}, + publisher = {Ink & Switch}, + year = {2019}, + visited = {2019-12-18}, +} diff --git a/root/articles/mmmfs/references/poc-or-gtfo/text$bibtex b/root/articles/mmmfs/references/poc-or-gtfo/text$bibtex new file mode 100644 index 0000000..26dda65 --- /dev/null +++ b/root/articles/mmmfs/references/poc-or-gtfo/text$bibtex @@ -0,0 +1,6 @@ +@article{PoC:or:GTFO, + author = {Albertini, Ange}, + title = {Abusing file formats; or, Corkami, the Novella}, + year = {2015}, + journal = {PoC||GTFO 7}, +} diff --git a/root/articles/mmmfs/references/subtext/URL -> cite$acm b/root/articles/mmmfs/references/subtext/URL -> cite$acm new file mode 100644 index 0000000..505b6ee --- /dev/null +++ b/root/articles/mmmfs/references/subtext/URL -> cite$acm @@ -0,0 +1 @@ +https://dl.acm.org/citation.cfm?id=1094851 diff --git a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon index f6c9cca..8034805 100644 --- a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon @@ -28,9 +28,8 @@ table.insert args, style: { 'list-style': 'none', 'font-size': '0.8em' } ol table.unpack args - -- @TODO: s/filesystem/a way of organizing files/g - append h1 'mmmfs', style: { 'margin-bottom': 0 } - append p "a file and operating system to live in", style: { 'margin-top': 0, 'padding-bottom': '0.2em', 'border-bottom': '1px solid black' } + append h1 'Empowered End-User Computing', style: { 'margin-bottom': 0 } + append p "A Historical Investigation and Development of a File-System-Based Environment", style: { 'margin-top': 0, 'padding-bottom': '0.2em', 'border-bottom': '1px solid black' } -- render a preview block do_section = (child) -> -- cgit v1.2.3 From 97055474ad6dfce6d66faeb2580fb31bbb1bfb2c Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 19 Dec 2019 20:47:48 +0100 Subject: more sidenote/reference features --- mmm/mmmfs/plugins/cites.moon | 64 +++++++++++++++++++++++++++++++------------- mmm/mmmfs/util.moon | 3 +++ scss/_browser.scss | 8 ++++++ scss/_content.scss | 2 +- scss/_reset.scss | 16 +++++++++-- scss/_sidenotes.scss | 24 +++++++++++++++++ 6 files changed, 96 insertions(+), 21 deletions(-) diff --git a/mmm/mmmfs/plugins/cites.moon b/mmm/mmmfs/plugins/cites.moon index 0223807..04e809d 100644 --- a/mmm/mmmfs/plugins/cites.moon +++ b/mmm/mmmfs/plugins/cites.moon @@ -1,13 +1,32 @@ -import div, a, i, b from require 'mmm.dom' +import div, span, sup, a, i, b from require 'mmm.dom' + +parse_bibtex = (src) -> + type, key, kv = src\match '@(%w+){(.-),(.*)}' + with info = { _type: type, _key: key } + for key, val in kv\gmatch '([a-z]-)%s*=%s*{(.-)}' + info[key] = val title = (info) -> assert info.title, "cite doesn't have title" inner = i info.title if info.url - a inner, href: info.url + a inner, href: info.url, style: display: 'inline' else b inner +format_full = (info) -> + tt = title info + dot, com = if info.title\match '[.?!]$' then '', '' else '.', ',' + switch info._type + when 'book', 'article' + span "#{info.author} (#{info.year}), ", tt, "#{dot} #{info.publisher}" + when 'web' + -- note = if info.note then ", #{info.note}" else '' + visited = if info.visited then " from #{info.visited}" else "" + span tt, "#{com} #{info.url}#{visited}" + else + span "#{info.author} (#{info.year}), ", tt, "#{dot} #{info.publisher}" + { converts: { { @@ -26,22 +45,31 @@ title = (info) -> inp: 'text/bibtex' out: 'mmm/dom' cost: 1 - transform: (src) => - type, key, kv = src\match '@(%w+){(.-),(.*)}' - info = {} - for key, val in kv\gmatch '([a-z]-)%s*=%s*{(.-)}' - info[key] = val - - tt = title info - dot, com = if info.title\match '[.?!]$' then '', '' else '.', ',' - switch type - when 'book', 'article' - div "#{info.author} (#{info.year}), ", tt, "#{dot} #{info.publisher}" - when 'web' - -- note = if info.note then ", #{info.note}" else '' - div tt, "#{com} #{info.url} from #{info.visited}" - else - div "#{info.author} (#{info.year}), ", tt, "#{dot} #{info.publisher}" + transform: (bib) => format_full parse_bibtex bib + } + { + inp: 'text/bibtex' + out: 'mmm/dom+link' + cost: 1 + transform: (bib) => + info = parse_bibtex bib + note = format_full info + + key = tostring 1 + id = "sideref-#{key}" + + intext = sup a key, href: "##{id}" + + span intext, div { + class: 'sidenote' + style: + 'margin-top': '-1rem' + + div :id, class: 'hook' + b key, class: 'ref' + ' ' + note + } } } } diff --git a/mmm/mmmfs/util.moon b/mmm/mmmfs/util.moon index 970dd42..8887187 100644 --- a/mmm/mmmfs/util.moon +++ b/mmm/mmmfs/util.moon @@ -53,6 +53,9 @@ tourl = (path) -> link_to = (fileder, name, origin, attr) -> fileder = find_fileder fileder, origin + link = fileder\get 'mmm/dom+link' + return link if link + name or= fileder\get 'title: mmm/dom' name or= fileder\gett 'name: alpha' diff --git a/scss/_browser.scss b/scss/_browser.scss index adf9dd1..118842f 100644 --- a/scss/_browser.scss +++ b/scss/_browser.scss @@ -26,6 +26,14 @@ background: inherit; } + .subnav { + display: flex; + flex: 0; + background: $gray-darker; + border-bottom: 2px solid $gray-dark; + padding: 0.5em; + } + .content { margin: 0; padding: 0; diff --git a/scss/_content.scss b/scss/_content.scss index ad854de..a5b626a 100644 --- a/scss/_content.scss +++ b/scss/_content.scss @@ -5,8 +5,8 @@ } .markdown { - max-width: 640px; position: relative; + max-width: 640px; &.wide { max-width: max-content; diff --git a/scss/_reset.scss b/scss/_reset.scss index 396c3e7..724624d 100644 --- a/scss/_reset.scss +++ b/scss/_reset.scss @@ -13,6 +13,11 @@ body, html, h1, h2, h3, h4, h5, h6 { } h1, h2, h3, h4, h5, h6 { font-weight: bold; } +h1 { font-size: 1.6em; } +h2 { font-size: 1.4em; } +h3 { font-size: 1.17em; } +h4, h5, h6 { font-size: 1em; } + input, select, button { color: initial; &:disabled { @@ -23,10 +28,16 @@ tt, code, kbd, samp { font-family: monospace; } code { font-size: 0.8em; } b, strong { font-weight: bold; } em, i { font-style: italic; } -a { font-size: 1em; cursor: pointer; } hr { clear: both; } ul { margin: 0; } +sup, sub { + vertical-align: baseline; + position: relative; + top: -0.4em; +} +sub { top: 0.4em; } + body { display: flex; flex-direction: column; @@ -40,11 +51,12 @@ body { a { display: inline-block; - + font-size: 1em; font-weight: bold; text-decoration: underline; text-decoration-color: transparent; + cursor: pointer; &:hover { filter: invert(40%); text-decoration-color: currentColor; diff --git a/scss/_sidenotes.scss b/scss/_sidenotes.scss index eddebc1..28b1494 100644 --- a/scss/_sidenotes.scss +++ b/scss/_sidenotes.scss @@ -20,6 +20,30 @@ $sidenote-width: 14rem; font-size: 0.8em; word-break: break-word; + .hook { + position: absolute; + top: -4rem; + width: 0; + height: 0; + + @media print { + top: 0; + } + } + + .ref { + display: block; + position: absolute; + + width: 1rem; + margin-left: -1.2rem; + text-align: right; + } + + a { + display: inline; + } + @include media-medium { width: initial; position: initial; -- cgit v1.2.3 From a02ae9cec3aec9f8781ab026239b639ffc1487fc Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 20 Dec 2019 15:06:33 +0100 Subject: add support for nested sidenotes --- mmm/mmmfs/plugins/markdown.moon | 6 ++++++ scss/_sidenotes.scss | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/mmm/mmmfs/plugins/markdown.moon b/mmm/mmmfs/plugins/markdown.moon index afa0307..35d7162 100644 --- a/mmm/mmmfs/plugins/markdown.moon +++ b/mmm/mmmfs/plugins/markdown.moon @@ -43,6 +43,12 @@ assert markdown, "no markdown implementation found" cost: 1 transform: (md) => "
#{markdown md}
" } + { + inp: 'text/markdown%+sidenotes' + out: 'text/html+frag' + cost: 1 + transform: (md) => "
#{markdown md}
" + } { inp: 'text/markdown%+span' out: 'text/html+frag' diff --git a/scss/_sidenotes.scss b/scss/_sidenotes.scss index 28b1494..c003496 100644 --- a/scss/_sidenotes.scss +++ b/scss/_sidenotes.scss @@ -7,6 +7,11 @@ $sidenote-width: 14rem; margin: auto; } + .sidenote-container & { + margin-right: initial; + margin: initial; + } + .sidenote { position: absolute; box-sizing: border-box; -- cgit v1.2.3 From 6e236eca27e9fafcd8eb628975496368a8197117 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 20 Dec 2019 15:07:08 +0100 Subject: make mmmfs contents sidenote-mds --- .../mmmfs/abstract/text$markdown+sidenotes.md | 0 root/articles/mmmfs/abstract/text$markdown.md | 0 .../mmmfs/evaluation/text$markdown+sidenotes.md | 166 +++++++++++++++++++ root/articles/mmmfs/evaluation/text$markdown.md | 166 ------------------- .../examples/intro: text$markdown+sidenotes.md | 91 +++++++++++ .../mmmfs/examples/intro: text$markdown.md | 91 ----------- .../mmmfs/framework/text$markdown+sidenotes.md | 105 ++++++++++++ root/articles/mmmfs/framework/text$markdown.md | 105 ------------ .../mmmfs/mmmfs/text$markdown+sidenotes.md | 180 +++++++++++++++++++++ root/articles/mmmfs/mmmfs/text$markdown.md | 180 --------------------- .../problem-statement/text$markdown+sidenotes.md | 128 +++++++++++++++ .../mmmfs/problem-statement/text$markdown.md | 128 --------------- 12 files changed, 670 insertions(+), 670 deletions(-) create mode 100644 root/articles/mmmfs/abstract/text$markdown+sidenotes.md delete mode 100644 root/articles/mmmfs/abstract/text$markdown.md create mode 100644 root/articles/mmmfs/evaluation/text$markdown+sidenotes.md delete mode 100644 root/articles/mmmfs/evaluation/text$markdown.md create mode 100644 root/articles/mmmfs/examples/intro: text$markdown+sidenotes.md delete mode 100644 root/articles/mmmfs/examples/intro: text$markdown.md create mode 100644 root/articles/mmmfs/framework/text$markdown+sidenotes.md delete mode 100644 root/articles/mmmfs/framework/text$markdown.md create mode 100644 root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md delete mode 100644 root/articles/mmmfs/mmmfs/text$markdown.md create mode 100644 root/articles/mmmfs/problem-statement/text$markdown+sidenotes.md delete mode 100644 root/articles/mmmfs/problem-statement/text$markdown.md diff --git a/root/articles/mmmfs/abstract/text$markdown+sidenotes.md b/root/articles/mmmfs/abstract/text$markdown+sidenotes.md new file mode 100644 index 0000000..e69de29 diff --git a/root/articles/mmmfs/abstract/text$markdown.md b/root/articles/mmmfs/abstract/text$markdown.md deleted file mode 100644 index e69de29..0000000 diff --git a/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md b/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md new file mode 100644 index 0000000..773c842 --- /dev/null +++ b/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md @@ -0,0 +1,166 @@ +evaluation +========== + +## examples +### publishing and blogging +Since mmmfs has grown out of the need for a versatile CMS for a personal publishing website, it is not surprising to +to see that it is still up to that job. Nevertheless it is worth taking a look at its strengths and weaknesses in this +context: + +The system has proven itself perfect for publishing small- and medium-size articles and blog posts, especially for its +ability to flexibly transclude content from any source. This includes diagrams (such as in this thesis), +videos (as in the documentation in the appendix), but also less conventional media such as +interactive diagrams or twitter postings. + +On the other hand, the development of the technical framework for this very thesis has posed greater challenges. +In particular, the implementation of the reference and sidenote systems are brittle and uninspiring. + +This is mostly due to the approach of splitting up the thesis into a multitude of fileders, and the current lack of +mechanisms to re-capture information spread throughout the resulting history effectively. +Another issue is that the system is currently based on the presumption that content can and should be interpreted +separate from its parent and context in most cases. This has made the implementation of sidenotes less idiomatic +than initially anticipated. + +### pinwall +The pinwall example shows some strenghts of the mmmfs system pretty convincingly. +The type coercion layer completely abstracts away the complexities of transcluding different types of content, +and only positioning and sizing the content, as well as enabling interaction, remain to handle in the pinwall fileder. + +A great benefit of the use of mmmfs versus other technology for realising this example is that the example can +seamlessly embed not only plain text, markdown, images, videos, and interactive widgets, but also follow links to all +of these types of content, and display them meaningfully. Accomplishing this with traditional frameworks would take +great effort, where mmmfs benefits from the reuse of these conversions across the whole system. + +In addition, the script for the pinwall folder is 120 lines long, of which 30 lines are styling, while almost 60 lines +take care of capturing and handling JS events. The bulk of complexity is therefore shifted towards interacting with the +UI layer (in this case the browser), which could feasibly be simplified through a custom abstraction layer or the use of +output means other than the web. + +### slideshow +A simplified image slideshow example consists of only 20 lines of code and demonstrates how the reactive component +framework simplifies the generation of ad-hoc UI dramatically: + +```moon +import ReactiveVar, text, elements from require 'mmm.component' +import div, a, img from elements + +=> + index = ReactiveVar 1 + + prev = (i) -> math.max 1, i - 1 + next = (i) -> math.min #@children, i + 1 + + div { + div { + a 'prev', href: '#', onclick: -> index\transform prev + index\map (i) -> text " image ##{i} " + a 'next', href: '#', onclick: -> index\transform next + }, + index\map (i) -> + child = assert @children[i], "image not found!" + img src: @children[i]\gett 'URL -> image/png' + } +``` + +The presentation framework is a bit longer, but the added complexity is again required to deal with browser quirks, +such as the fullscreen API and sizing content proportionally to the viewport size. +The parts of the code dealing with the content are essentially identical, except that content is transcluded via the +more general `mmm/dom` type-interface, allowing for a greater variety of types of content to be used as slides. + +## general concerns +While the system has proven pretty successfuly and moldable to the different use-cases that it has been tested in, +there are also limitations in the proposed system that have become obvious in developing and working with the system. +Some of these have been anticipated for some time and concrete research directions for solutions are apparent, +while others may be intrinsic limitations in the approach taken. + +### global set of converts +In the current system, there exists only a single, global set of *converts* that can be potentially applied +to facets anywhere in the system. +Therefore it is necessary to encode behaviour directly (as code) in facets wherever exceptional behaviour is required. +For example if a fileder conatining multiple images wants to provide custom UI for each image when viewed independently, +this code has to either be attached to every image individually (and redundantly), or added as a global convert. +To make sure this convert does not interfere with images elsewhere in the system, it would be necessary to introduce +a new type and change the images to use it, which may present more problems yet and works against the principle of +compatibility the system has been constructed for. + +A potential direction of research in the future is to allow specifying *converts* as part of the fileder tree. +Application of *converts* could then be scoped to their fileders' subtrees, such that for any facet only the *converts* +stored in the chain of its parents upwards are considered. +This way, *converts* can be added locally if they only make sense within a given context. +Additionally it could be made possible to use this mechanism to locally override *converts* inherited from +further up in the tree, for example to specialize types based on their context in the system. + +The biggest downside to this approach would be that it presents another pressure factor for, +while also reincforcing, the hierarchical organization of data, +thereby exacerbating the limits of hierarchical structures.
see also +
+ +### code outside of the system +At the moment, a large part of the mmmfs codebase is still separate from the content, and developed outside of mmmfs +itself. This is a result of the development process of mmmfs and was necessary to start the project as the filesystem +itself matured, but has become a limitation of the user experience now: Potential users of mmmfs would generally start +by becoming familiar with the operation of mmmfs from within the system, as this is the expected (and designated) +experience developed for them. All of the code that lives outside of the mmmfs tree is therefore invisible and opaque +to them, actively limiting their understanding, and thereby the customizability, of the system. + +This weakness represents a failure to (fully) implement the quality of a "Living System" as proposed by +*Ink and Switch*. + +In general however, some portion of code may always have to be left outside of the system. +This also wouldn't necessarily represent a problem, but in this case it is particularily relevant +for the global set of *converts* (see above), as well as the layout used to render the web view, +both of which are expected to undergo changes as users adapt the system to their own content types and +domains of interest, as well as their visual identity, respectively. + +### type system +The currently used type system based on strings and pattern matching has been largely satisfactory, +but has proven problematic for some anticipated use cases. +It should be considered to switch to a more intricate, +structural type system that allows encoding more concrete meta-data alongside the type, +and to match *converts* based on a more flexible scheme of pattern matching. +For example it is envisaged to store the resolution of an image file in its type. +Many *converts* might choose to ignore this additional information, +but others could use this information to generate lower-resolution 'thumbnails' of images automatically. +Using these mechanisms for example images could be requested with a maximum-resolution constraint to save on bandwidth +when embedded in other documents. + +### type-coercion +By giving the system more information about the data it is dealing with, +and then relying on the system to automatically transform between data-types, +it is easy to lose track of which format data is concretely stored in. +In much the same way that the application-centric paradigm alienates users from an understanding +and feeling of ownership of their data by overemphasizing the tools in between, +the automagical coercion of data types introduces distance between the user and +an understanding of the data in the system. +This poses a threat to the transparency of the system, and a potential lack of the quality of "Embodiment" (see above). + +Potential solutions could be to communicate the conversion path clearly and explicitly together with the content, +as well as making this display interactive to encourage experimentation with custom conversion queries. +Emphasising the conversion process more strongly in this way might be able to turn this feature from an opaque +hindrance into a transparent tool using careful UX and UI design. + +### editing +Because many *converts* are not necessarily reversible, +it is very hard to implement generic ways of editing stored data in the same format it is viewed. +For example, the system trivially converts markdown-formatted text sources into viewable HTML markup, +but it is hardly possible to propagate changes to the viewable HTML back to the markdown source. +This particular instance of the problem might be solvable using a Rich-Text editor, but the general problem +worsens when the conversion path becomes more complex: +If the markdown source was fetched via HTTP from a remote URL (e.g. if the facet's type was `URL -> text/markdown`), +it is not possible to edit the content at all, since the only data owned by the system is the URL string itself, +which is not part of the viewable representation at all. +Similarily, when viewing output that is generated by code (e.g. `text/moonscript -> mmm/dom`), +the code itself is not visible to the user when interacting with the viewable representation, +and if the user wishes to change parts of the representation the system is unable to relate these changes to elements +of the code or assist the user in doing so. + +However even where plain text is used and edited, a shortcoming of the current approach to editing is evident: +The content editor is wholly separate from the visible representation, and only facets of the currently viewed +fileder can be edited. This means that content cannot be edited in its context, which is particularily annoying +due to the fragmentation of content that mmmfs encourages. + +As a result, the experiences of interacting with the system at large is still a very different experience than +editing content (and thereby extending the system) in it. This is expected to represent a major hurdle for users +getting started with the system, and is a major shortcoming in enabling end-user programming as set as a goal for +this project. A future iteration should take care to reconsider how editing can be integrated more holistically +with the other core concepts of the design. diff --git a/root/articles/mmmfs/evaluation/text$markdown.md b/root/articles/mmmfs/evaluation/text$markdown.md deleted file mode 100644 index 773c842..0000000 --- a/root/articles/mmmfs/evaluation/text$markdown.md +++ /dev/null @@ -1,166 +0,0 @@ -evaluation -========== - -## examples -### publishing and blogging -Since mmmfs has grown out of the need for a versatile CMS for a personal publishing website, it is not surprising to -to see that it is still up to that job. Nevertheless it is worth taking a look at its strengths and weaknesses in this -context: - -The system has proven itself perfect for publishing small- and medium-size articles and blog posts, especially for its -ability to flexibly transclude content from any source. This includes diagrams (such as in this thesis), -videos (as in the documentation in the appendix), but also less conventional media such as -interactive diagrams or twitter postings. - -On the other hand, the development of the technical framework for this very thesis has posed greater challenges. -In particular, the implementation of the reference and sidenote systems are brittle and uninspiring. - -This is mostly due to the approach of splitting up the thesis into a multitude of fileders, and the current lack of -mechanisms to re-capture information spread throughout the resulting history effectively. -Another issue is that the system is currently based on the presumption that content can and should be interpreted -separate from its parent and context in most cases. This has made the implementation of sidenotes less idiomatic -than initially anticipated. - -### pinwall -The pinwall example shows some strenghts of the mmmfs system pretty convincingly. -The type coercion layer completely abstracts away the complexities of transcluding different types of content, -and only positioning and sizing the content, as well as enabling interaction, remain to handle in the pinwall fileder. - -A great benefit of the use of mmmfs versus other technology for realising this example is that the example can -seamlessly embed not only plain text, markdown, images, videos, and interactive widgets, but also follow links to all -of these types of content, and display them meaningfully. Accomplishing this with traditional frameworks would take -great effort, where mmmfs benefits from the reuse of these conversions across the whole system. - -In addition, the script for the pinwall folder is 120 lines long, of which 30 lines are styling, while almost 60 lines -take care of capturing and handling JS events. The bulk of complexity is therefore shifted towards interacting with the -UI layer (in this case the browser), which could feasibly be simplified through a custom abstraction layer or the use of -output means other than the web. - -### slideshow -A simplified image slideshow example consists of only 20 lines of code and demonstrates how the reactive component -framework simplifies the generation of ad-hoc UI dramatically: - -```moon -import ReactiveVar, text, elements from require 'mmm.component' -import div, a, img from elements - -=> - index = ReactiveVar 1 - - prev = (i) -> math.max 1, i - 1 - next = (i) -> math.min #@children, i + 1 - - div { - div { - a 'prev', href: '#', onclick: -> index\transform prev - index\map (i) -> text " image ##{i} " - a 'next', href: '#', onclick: -> index\transform next - }, - index\map (i) -> - child = assert @children[i], "image not found!" - img src: @children[i]\gett 'URL -> image/png' - } -``` - -The presentation framework is a bit longer, but the added complexity is again required to deal with browser quirks, -such as the fullscreen API and sizing content proportionally to the viewport size. -The parts of the code dealing with the content are essentially identical, except that content is transcluded via the -more general `mmm/dom` type-interface, allowing for a greater variety of types of content to be used as slides. - -## general concerns -While the system has proven pretty successfuly and moldable to the different use-cases that it has been tested in, -there are also limitations in the proposed system that have become obvious in developing and working with the system. -Some of these have been anticipated for some time and concrete research directions for solutions are apparent, -while others may be intrinsic limitations in the approach taken. - -### global set of converts -In the current system, there exists only a single, global set of *converts* that can be potentially applied -to facets anywhere in the system. -Therefore it is necessary to encode behaviour directly (as code) in facets wherever exceptional behaviour is required. -For example if a fileder conatining multiple images wants to provide custom UI for each image when viewed independently, -this code has to either be attached to every image individually (and redundantly), or added as a global convert. -To make sure this convert does not interfere with images elsewhere in the system, it would be necessary to introduce -a new type and change the images to use it, which may present more problems yet and works against the principle of -compatibility the system has been constructed for. - -A potential direction of research in the future is to allow specifying *converts* as part of the fileder tree. -Application of *converts* could then be scoped to their fileders' subtrees, such that for any facet only the *converts* -stored in the chain of its parents upwards are considered. -This way, *converts* can be added locally if they only make sense within a given context. -Additionally it could be made possible to use this mechanism to locally override *converts* inherited from -further up in the tree, for example to specialize types based on their context in the system. - -The biggest downside to this approach would be that it presents another pressure factor for, -while also reincforcing, the hierarchical organization of data, -thereby exacerbating the limits of hierarchical structures.
see also -
- -### code outside of the system -At the moment, a large part of the mmmfs codebase is still separate from the content, and developed outside of mmmfs -itself. This is a result of the development process of mmmfs and was necessary to start the project as the filesystem -itself matured, but has become a limitation of the user experience now: Potential users of mmmfs would generally start -by becoming familiar with the operation of mmmfs from within the system, as this is the expected (and designated) -experience developed for them. All of the code that lives outside of the mmmfs tree is therefore invisible and opaque -to them, actively limiting their understanding, and thereby the customizability, of the system. - -This weakness represents a failure to (fully) implement the quality of a "Living System" as proposed by -*Ink and Switch*. - -In general however, some portion of code may always have to be left outside of the system. -This also wouldn't necessarily represent a problem, but in this case it is particularily relevant -for the global set of *converts* (see above), as well as the layout used to render the web view, -both of which are expected to undergo changes as users adapt the system to their own content types and -domains of interest, as well as their visual identity, respectively. - -### type system -The currently used type system based on strings and pattern matching has been largely satisfactory, -but has proven problematic for some anticipated use cases. -It should be considered to switch to a more intricate, -structural type system that allows encoding more concrete meta-data alongside the type, -and to match *converts* based on a more flexible scheme of pattern matching. -For example it is envisaged to store the resolution of an image file in its type. -Many *converts* might choose to ignore this additional information, -but others could use this information to generate lower-resolution 'thumbnails' of images automatically. -Using these mechanisms for example images could be requested with a maximum-resolution constraint to save on bandwidth -when embedded in other documents. - -### type-coercion -By giving the system more information about the data it is dealing with, -and then relying on the system to automatically transform between data-types, -it is easy to lose track of which format data is concretely stored in. -In much the same way that the application-centric paradigm alienates users from an understanding -and feeling of ownership of their data by overemphasizing the tools in between, -the automagical coercion of data types introduces distance between the user and -an understanding of the data in the system. -This poses a threat to the transparency of the system, and a potential lack of the quality of "Embodiment" (see above). - -Potential solutions could be to communicate the conversion path clearly and explicitly together with the content, -as well as making this display interactive to encourage experimentation with custom conversion queries. -Emphasising the conversion process more strongly in this way might be able to turn this feature from an opaque -hindrance into a transparent tool using careful UX and UI design. - -### editing -Because many *converts* are not necessarily reversible, -it is very hard to implement generic ways of editing stored data in the same format it is viewed. -For example, the system trivially converts markdown-formatted text sources into viewable HTML markup, -but it is hardly possible to propagate changes to the viewable HTML back to the markdown source. -This particular instance of the problem might be solvable using a Rich-Text editor, but the general problem -worsens when the conversion path becomes more complex: -If the markdown source was fetched via HTTP from a remote URL (e.g. if the facet's type was `URL -> text/markdown`), -it is not possible to edit the content at all, since the only data owned by the system is the URL string itself, -which is not part of the viewable representation at all. -Similarily, when viewing output that is generated by code (e.g. `text/moonscript -> mmm/dom`), -the code itself is not visible to the user when interacting with the viewable representation, -and if the user wishes to change parts of the representation the system is unable to relate these changes to elements -of the code or assist the user in doing so. - -However even where plain text is used and edited, a shortcoming of the current approach to editing is evident: -The content editor is wholly separate from the visible representation, and only facets of the currently viewed -fileder can be edited. This means that content cannot be edited in its context, which is particularily annoying -due to the fragmentation of content that mmmfs encourages. - -As a result, the experiences of interacting with the system at large is still a very different experience than -editing content (and thereby extending the system) in it. This is expected to represent a major hurdle for users -getting started with the system, and is a major shortcoming in enabling end-user programming as set as a goal for -this project. A future iteration should take care to reconsider how editing can be integrated more holistically -with the other core concepts of the design. diff --git a/root/articles/mmmfs/examples/intro: text$markdown+sidenotes.md b/root/articles/mmmfs/examples/intro: text$markdown+sidenotes.md new file mode 100644 index 0000000..a427ae8 --- /dev/null +++ b/root/articles/mmmfs/examples/intro: text$markdown+sidenotes.md @@ -0,0 +1,91 @@ +# examples +To illustrate the capabilities of the proposed system, and to compare the results with the framework introduced above, +a number of example use cases have been chosen and implemented from the perspective of a user. +In the following section I will introduce these use cases and briefly summarize the implementation +approach in terms of the capabilities of the proposed system. + +## publishing and blogging +### blogging +Blogging is pretty straightforward, since it generally just involves publishing lightly-formatted text, +interspersed with media such as images and videos or perhaps social media posts. +Markdown is a great tool for this job, and has been integrated in the system to much success: +There are two different types registered with *converts*: `text/markdown` and `text/markdown+span`. +They both render to HTML (and DOM nodes), so they are immediately viewable as part of the system. +The only difference for `text/markdown+span` is that it is limited to a single line, +and doesn't render as a paragraph but rather just a line of text. +This makes it suitable for denoting formatted-text titles and other small strings of text. + +The problem of embedding other content together with text comfortably is also solved easily, +becase Markdown allows embedding arbitrary HTML in the document. +This made it possible to define a set of pseudo-HTML elements in the Markdown-convert, +`` and ``, which respectively embed and link to other content native to mmm. + +### scientific publishing +
+One of the 'standard' solutions, LaTeX, +is arguably at least as complex as the mmm system proposed here, but has a much narrower scope, +since it does not support interaction. +
+Scientific publishing is notoriously complex, involving not only the transclusion of diagrams +and other media, but generally requiring precise and consistent control over formatting and layout. +Some of these complexities are tedious to manage, but present good opportunities for programmatic +systems and media to do work for the writer. + +One such topic is the topic of references. +References appear in various formats at multiple positions in a scientific document; +usually they are referenced via a reduced visual form within the text of the document, +and then shown again with full details at the end of the document. + +For the sake of this thesis, referencing has been implemented using a subset of the popular +BibTeX format for describing citations. Converts have been implemented for the `text/bibtex` +type to convert to a full reference format (to `mmm/dom`) and to an inline side-note reference +(`mmm/dom+link`) that can be transcluded using the `` pseudo-tag. + +For convenience, a convert from the `URL -> cite/acm` type has been provided to `URL -> text/bibtex`, +which generates links to the ACM Digital Library +API for accessing BibTeX citations for documents in the library. +This means that it is enough to store the link to the ACM DL entry in mmmfs, +and the reference will automatically be fetched (and track potential remote corrections). + +## pinwall +In many situations, in particular for creative work, it is often useful to compile resources of +different types for reference or inspiration, and arrange them spacially so that they can be viewed +at a glance or organized into different contexts etc. +Such a pinwall could serve for example to organise references to articles, +to collect visual inspiration for a moodboard etc. + +As a collection, the Pinwall is primarily mapped to a Fileder in the system. +Any content that is placed within can then be rendered by the Pinwall, +which can constrain every piece of content to a rectangular piece on its canvas. +This is possible through a simple script, e.g. of the type `text/moonscript -> fn -> mmm/dom`, +which enumerates the list of children, wraps each in such a rectangular container, +and outputs the list of containers as DOM elements. + +The position and size of each panel are stored in an ad-hoc facet, encoded in the JSON data format: +`pinwall_info: text/json`. This facet can then set on each child and accessed whenever the script is called +to render the children, plugging the values within the facet into the visual styling of the document. + +The script can also set event handlers that react to user input while the document is loaded, +and allow the user to reposition and resize the individual pinwall items by clicking and dragging +on the upper border or lower right-hand corner respectively. +Whenever a change is made the event handler can then update the value in the `pinwall_info` facet, +so that the script places the content at the updated position and size next time it is invoked. + +## slideshow +Another common use of digital documents is as aids in a verbal presentation. +These often take the form of slideshows, for the creation of which a number of established applications exist. +In simple terms, a slideshow is simply a linear series of screen-sized documents, that can be +advanced (and rewound) one by one using keypresses. + +The implementation of this is rather straightforward as well. +The slideshow as a whole becomes a fileder with a script that generates a designated viewport rectangle, +as well as a control interface with keys for advancing the active slide. +It also allows putting the browser into fullscreen mode to maximise screenspace and remove visual elements +of the website that may distract from the presentation, and register an event handler for keyboard accelerators +for moving through the presentation. + +Finally the script simply embeds the first of its child-fileders into the viewport rect. +One the current slide is changed, the next embedded child is simply chosen. + +## code documentation +/meta/mmm.dom/:%20text/html+interactive diff --git a/root/articles/mmmfs/examples/intro: text$markdown.md b/root/articles/mmmfs/examples/intro: text$markdown.md deleted file mode 100644 index a427ae8..0000000 --- a/root/articles/mmmfs/examples/intro: text$markdown.md +++ /dev/null @@ -1,91 +0,0 @@ -# examples -To illustrate the capabilities of the proposed system, and to compare the results with the framework introduced above, -a number of example use cases have been chosen and implemented from the perspective of a user. -In the following section I will introduce these use cases and briefly summarize the implementation -approach in terms of the capabilities of the proposed system. - -## publishing and blogging -### blogging -Blogging is pretty straightforward, since it generally just involves publishing lightly-formatted text, -interspersed with media such as images and videos or perhaps social media posts. -Markdown is a great tool for this job, and has been integrated in the system to much success: -There are two different types registered with *converts*: `text/markdown` and `text/markdown+span`. -They both render to HTML (and DOM nodes), so they are immediately viewable as part of the system. -The only difference for `text/markdown+span` is that it is limited to a single line, -and doesn't render as a paragraph but rather just a line of text. -This makes it suitable for denoting formatted-text titles and other small strings of text. - -The problem of embedding other content together with text comfortably is also solved easily, -becase Markdown allows embedding arbitrary HTML in the document. -This made it possible to define a set of pseudo-HTML elements in the Markdown-convert, -`` and ``, which respectively embed and link to other content native to mmm. - -### scientific publishing -
-One of the 'standard' solutions, LaTeX, -is arguably at least as complex as the mmm system proposed here, but has a much narrower scope, -since it does not support interaction. -
-Scientific publishing is notoriously complex, involving not only the transclusion of diagrams -and other media, but generally requiring precise and consistent control over formatting and layout. -Some of these complexities are tedious to manage, but present good opportunities for programmatic -systems and media to do work for the writer. - -One such topic is the topic of references. -References appear in various formats at multiple positions in a scientific document; -usually they are referenced via a reduced visual form within the text of the document, -and then shown again with full details at the end of the document. - -For the sake of this thesis, referencing has been implemented using a subset of the popular -BibTeX format for describing citations. Converts have been implemented for the `text/bibtex` -type to convert to a full reference format (to `mmm/dom`) and to an inline side-note reference -(`mmm/dom+link`) that can be transcluded using the `` pseudo-tag. - -For convenience, a convert from the `URL -> cite/acm` type has been provided to `URL -> text/bibtex`, -which generates links to the ACM Digital Library -API for accessing BibTeX citations for documents in the library. -This means that it is enough to store the link to the ACM DL entry in mmmfs, -and the reference will automatically be fetched (and track potential remote corrections). - -## pinwall -In many situations, in particular for creative work, it is often useful to compile resources of -different types for reference or inspiration, and arrange them spacially so that they can be viewed -at a glance or organized into different contexts etc. -Such a pinwall could serve for example to organise references to articles, -to collect visual inspiration for a moodboard etc. - -As a collection, the Pinwall is primarily mapped to a Fileder in the system. -Any content that is placed within can then be rendered by the Pinwall, -which can constrain every piece of content to a rectangular piece on its canvas. -This is possible through a simple script, e.g. of the type `text/moonscript -> fn -> mmm/dom`, -which enumerates the list of children, wraps each in such a rectangular container, -and outputs the list of containers as DOM elements. - -The position and size of each panel are stored in an ad-hoc facet, encoded in the JSON data format: -`pinwall_info: text/json`. This facet can then set on each child and accessed whenever the script is called -to render the children, plugging the values within the facet into the visual styling of the document. - -The script can also set event handlers that react to user input while the document is loaded, -and allow the user to reposition and resize the individual pinwall items by clicking and dragging -on the upper border or lower right-hand corner respectively. -Whenever a change is made the event handler can then update the value in the `pinwall_info` facet, -so that the script places the content at the updated position and size next time it is invoked. - -## slideshow -Another common use of digital documents is as aids in a verbal presentation. -These often take the form of slideshows, for the creation of which a number of established applications exist. -In simple terms, a slideshow is simply a linear series of screen-sized documents, that can be -advanced (and rewound) one by one using keypresses. - -The implementation of this is rather straightforward as well. -The slideshow as a whole becomes a fileder with a script that generates a designated viewport rectangle, -as well as a control interface with keys for advancing the active slide. -It also allows putting the browser into fullscreen mode to maximise screenspace and remove visual elements -of the website that may distract from the presentation, and register an event handler for keyboard accelerators -for moving through the presentation. - -Finally the script simply embeds the first of its child-fileders into the viewport rect. -One the current slide is changed, the next embedded child is simply chosen. - -## code documentation -/meta/mmm.dom/:%20text/html+interactive diff --git a/root/articles/mmmfs/framework/text$markdown+sidenotes.md b/root/articles/mmmfs/framework/text$markdown+sidenotes.md new file mode 100644 index 0000000..af446a5 --- /dev/null +++ b/root/articles/mmmfs/framework/text$markdown+sidenotes.md @@ -0,0 +1,105 @@ +Two of the earliest wholistic computing systems, the Xerox Alto and Xerox Star, both developed at Xerox PARC and introduced in the 70s and early 80s, pioneered not only graphical user-interfaces, but also the "Desktop Metaphor". +The desktop metaphor presents information as stored in "Documents" that can be organized in folders and on the "Desktop". It invokes a strong analogy to physical tools. +One of the differences between the Xerox Star system and other systems at the time, as well as the systems we use currently, is that the type of data a file represents is directly known to the system. + +
+ +> In a Desktop metaphor system, users deal mainly with data files, oblivious to the existence of programs. +> They do not "invoke a text editor", they "open a document". +> The system knows the type of each file and notifies the relevant application program when one is opened. +> +> The disadvantage of assigning data files to applications is that users sometimes want to operate on a file with a program other than +its "assigned" application. \[...\] +> Star's designers feel that, for its audience, the advantages of allowing users to forget +about programs outweighs this disadvantage. + +Other systems at the time lacked any knowledge of the type of files, +and while mainstream operating systems of today have retro-fit the ability to associate and memorize the preferred applications to use for a given file based on it's name suffix, the intention of making applications a secondary, technical detail of working with the computer has surely been lost. + +Another design detail of the Star system is the concept of "properties" that are stored for "objects" throughout the system (the objects being anything from files to characters or paragraphs). +These typed pieces of information are labelled with a name and persistently stored, providing a mechanism to store metadata such as user preference for ordering or defaut view of a folder for example. + +*** + +Fig. 8 - Star Retrospective + +The earliest indirect influence for the Xerox Alto and many other systems of its time, +was the *Memex*. The *Memex* is a hypothetical device and system for knowledge management. +Proposed by Vannevar Bush in 1945, the concept predates much of the technology that later was used to implement many parts of the vision. In essence, the concept of hypertext was invented. + +*** + +One of the systems that could be said to have come closest to a practical implementation of the Memex might be Apple's *Hypercard*. + +https://archive.org/details/CC501_hypercard + +"So I can have the information in these stacks tied together in a way that makes sense" + +In a demonstration video, the creators of the software showcase a system of stacks of cards that together implement, amongst others, a calendar (with yearly and weekly views), a list of digital business cards for storing phone numbers and addresses, and a todo list. +However these stacks of cards are not just usable by themselves, it is also demonstrated how stacks can link to each other in meaningful ways, such as jumping to the card corresponding to a specific day from the yearly calendar view, or automatically looking up the card corresponding to a person's first name from a mention of the name in the text on a different card. + +Alongside Spreadsheets, *Hypercard* remains one of the most successful implementations of end-user programming, even today. +While it's technical abilities have been long matched and passed by other software (such as the ubiquitous HTML hypertext markup language), these technical successors have failed the legacy of *Hypercard* as an end-user tool: +while it is easier than ever to publish content on the web (through various social media and microblogging services), the benefits of hypermedia as a customizable medium for personal management have nearly vanished. +End-users do not create hypertext anymore. + +The *UNIX Philosophy* +describes the software design paradigm pioneered in the creation of the Unix operating system at the AT&T Bell Labs +research center in the 1960s. The concepts are considered quite influental and are still notably applied in the Linux community. +Many attempts at summaries exist, but the following includes the pieces that are especially relevant even today: + +> Even though the UNIX system introduces a number of innovative programs and techniques, no single program or idea makes it work well. +> Instead, what makes it effective is the approach to programming, a philosophy of using the computer. Although that philosophy can't be +> written down in a single sentence, at its heart is the idea that the power of a system comes more from the relationships among programs +> than from the programs themselves. Many UNIX programs do quite trivial things in isolation, but, combined with other programs, +> become general and useful tools. + +This approach has multiple benefits with regard to end-user programmability: +Assembling the system out of simple, modular pieces means that for any given task a user may want to implement, +it is very likely that preexisting parts of the system can help the user realize a solution. +Wherever such a preexisting part exists, it pays off designing it in such a way that it is easy to integrate for the user later. +Assembling the system as a collection of modular, interacting pieces also enables future growth and customization, +since pieces may be swapped out with customized or alternate software at any time. + +*** + +Based on this, a modern data storage and processing ecosystem should enable transclusion of both content and behaviours +between contexts. +Content should be able to be transcluded and referenced to facilitate the creation of flexible data formats and interactions, +such that e.g. a slideshow slide can include content in a variety other formats (such as images and text) from anywhere else in the system. +Behaviours should be able to be transcluded and reused to facilitate the creation of ad-hoc sytems and applets based on user needs. +For example a user-created todo list should be able to take advantage of a sketching tool the user already has access to. + +The system should enable the quick creation of ad-hoc software. + +While there are drawbacks to cloud-storage of data (as outlined above), the utility of distributed systems is acknowledged, +and the system should therefore be able to include content and behaviours via the network. +This ability should be integrated deeply into the system, +so that data can be treated independently of its origin and storage conditions, with as little caveats as possible. + +The system needs to be browsable and understandable by users. + +In order to provide users full access to their information as well as the computational infrastructure, +users need to be able to finely customize and reorganize the smallest pieces to suit their own purposes, +in other words: be able to program. + +While there is an ongoing area of research focusing on the development of new programming paradigms, +methodologies and tools that are more accessible and cater to the wide +range of end-users, +in order to keep the scope of this work appropriate, +conventional programming languages are used for the time being. +Confidence is placed in the fact that eventually more user-friendly languages will be available and, +given the goal of modularity, should be implementable in a straightforward fashion. + +*Ink and Switch* suggest three qualities for tools striving to support +end-user programming: + +- "Embodiment", i.e. reifying central concepts of the programming model as more concrete, tangible objects + in the digital space (for example through visual representation), + in order to reduce cognitive load on the user. +- "Living System", by which they seem to describe the malleability of a system or environment, + and in particular the ability to make changes at different levels of depth in the system with + very short feedback loops and a feeling of direct experience. +- "In-place toolchain", denoting the availability of tools to customize and author the experience, + as well as a certain accesibility of these tools, granted by a conceptual affinity between the + use of the tools and general 'passive' use of containing system at large. diff --git a/root/articles/mmmfs/framework/text$markdown.md b/root/articles/mmmfs/framework/text$markdown.md deleted file mode 100644 index af446a5..0000000 --- a/root/articles/mmmfs/framework/text$markdown.md +++ /dev/null @@ -1,105 +0,0 @@ -Two of the earliest wholistic computing systems, the Xerox Alto and Xerox Star, both developed at Xerox PARC and introduced in the 70s and early 80s, pioneered not only graphical user-interfaces, but also the "Desktop Metaphor". -The desktop metaphor presents information as stored in "Documents" that can be organized in folders and on the "Desktop". It invokes a strong analogy to physical tools. -One of the differences between the Xerox Star system and other systems at the time, as well as the systems we use currently, is that the type of data a file represents is directly known to the system. - -
- -> In a Desktop metaphor system, users deal mainly with data files, oblivious to the existence of programs. -> They do not "invoke a text editor", they "open a document". -> The system knows the type of each file and notifies the relevant application program when one is opened. -> -> The disadvantage of assigning data files to applications is that users sometimes want to operate on a file with a program other than -its "assigned" application. \[...\] -> Star's designers feel that, for its audience, the advantages of allowing users to forget -about programs outweighs this disadvantage. - -Other systems at the time lacked any knowledge of the type of files, -and while mainstream operating systems of today have retro-fit the ability to associate and memorize the preferred applications to use for a given file based on it's name suffix, the intention of making applications a secondary, technical detail of working with the computer has surely been lost. - -Another design detail of the Star system is the concept of "properties" that are stored for "objects" throughout the system (the objects being anything from files to characters or paragraphs). -These typed pieces of information are labelled with a name and persistently stored, providing a mechanism to store metadata such as user preference for ordering or defaut view of a folder for example. - -*** - -Fig. 8 - Star Retrospective - -The earliest indirect influence for the Xerox Alto and many other systems of its time, -was the *Memex*. The *Memex* is a hypothetical device and system for knowledge management. -Proposed by Vannevar Bush in 1945, the concept predates much of the technology that later was used to implement many parts of the vision. In essence, the concept of hypertext was invented. - -*** - -One of the systems that could be said to have come closest to a practical implementation of the Memex might be Apple's *Hypercard*. - -https://archive.org/details/CC501_hypercard - -"So I can have the information in these stacks tied together in a way that makes sense" - -In a demonstration video, the creators of the software showcase a system of stacks of cards that together implement, amongst others, a calendar (with yearly and weekly views), a list of digital business cards for storing phone numbers and addresses, and a todo list. -However these stacks of cards are not just usable by themselves, it is also demonstrated how stacks can link to each other in meaningful ways, such as jumping to the card corresponding to a specific day from the yearly calendar view, or automatically looking up the card corresponding to a person's first name from a mention of the name in the text on a different card. - -Alongside Spreadsheets, *Hypercard* remains one of the most successful implementations of end-user programming, even today. -While it's technical abilities have been long matched and passed by other software (such as the ubiquitous HTML hypertext markup language), these technical successors have failed the legacy of *Hypercard* as an end-user tool: -while it is easier than ever to publish content on the web (through various social media and microblogging services), the benefits of hypermedia as a customizable medium for personal management have nearly vanished. -End-users do not create hypertext anymore. - -The *UNIX Philosophy* -describes the software design paradigm pioneered in the creation of the Unix operating system at the AT&T Bell Labs -research center in the 1960s. The concepts are considered quite influental and are still notably applied in the Linux community. -Many attempts at summaries exist, but the following includes the pieces that are especially relevant even today: - -> Even though the UNIX system introduces a number of innovative programs and techniques, no single program or idea makes it work well. -> Instead, what makes it effective is the approach to programming, a philosophy of using the computer. Although that philosophy can't be -> written down in a single sentence, at its heart is the idea that the power of a system comes more from the relationships among programs -> than from the programs themselves. Many UNIX programs do quite trivial things in isolation, but, combined with other programs, -> become general and useful tools. - -This approach has multiple benefits with regard to end-user programmability: -Assembling the system out of simple, modular pieces means that for any given task a user may want to implement, -it is very likely that preexisting parts of the system can help the user realize a solution. -Wherever such a preexisting part exists, it pays off designing it in such a way that it is easy to integrate for the user later. -Assembling the system as a collection of modular, interacting pieces also enables future growth and customization, -since pieces may be swapped out with customized or alternate software at any time. - -*** - -Based on this, a modern data storage and processing ecosystem should enable transclusion of both content and behaviours -between contexts. -Content should be able to be transcluded and referenced to facilitate the creation of flexible data formats and interactions, -such that e.g. a slideshow slide can include content in a variety other formats (such as images and text) from anywhere else in the system. -Behaviours should be able to be transcluded and reused to facilitate the creation of ad-hoc sytems and applets based on user needs. -For example a user-created todo list should be able to take advantage of a sketching tool the user already has access to. - -The system should enable the quick creation of ad-hoc software. - -While there are drawbacks to cloud-storage of data (as outlined above), the utility of distributed systems is acknowledged, -and the system should therefore be able to include content and behaviours via the network. -This ability should be integrated deeply into the system, -so that data can be treated independently of its origin and storage conditions, with as little caveats as possible. - -The system needs to be browsable and understandable by users. - -In order to provide users full access to their information as well as the computational infrastructure, -users need to be able to finely customize and reorganize the smallest pieces to suit their own purposes, -in other words: be able to program. - -While there is an ongoing area of research focusing on the development of new programming paradigms, -methodologies and tools that are more accessible and cater to the wide -range of end-users, -in order to keep the scope of this work appropriate, -conventional programming languages are used for the time being. -Confidence is placed in the fact that eventually more user-friendly languages will be available and, -given the goal of modularity, should be implementable in a straightforward fashion. - -*Ink and Switch* suggest three qualities for tools striving to support -end-user programming: - -- "Embodiment", i.e. reifying central concepts of the programming model as more concrete, tangible objects - in the digital space (for example through visual representation), - in order to reduce cognitive load on the user. -- "Living System", by which they seem to describe the malleability of a system or environment, - and in particular the ability to make changes at different levels of depth in the system with - very short feedback loops and a feeling of direct experience. -- "In-place toolchain", denoting the availability of tools to customize and author the experience, - as well as a certain accesibility of these tools, granted by a conceptual affinity between the - use of the tools and general 'passive' use of containing system at large. diff --git a/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md b/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md new file mode 100644 index 0000000..7a682dd --- /dev/null +++ b/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md @@ -0,0 +1,180 @@ +# mmmfs +`mmmfs` seeks to improve on two fronts. + +One of the main driving ideas of the mmmfs is to help data portability and use by making it simpler to inter-operate with different data formats. +This is accomplished using two major components, the *Type System and Coercion Engine* and the *Fileder Unified Data Model* for unified data storage and access. + +## the fileder unified data model +The Fileder Model is the underlying unified data storage model. +Like many data storage models it is based fundamentally on the concept of a hierarchical tree-structure. + +schematic view of an example tree in a mainstream filesystem + +In common filesystems, as pictured, data can be organized hierarchically into *folders* (or *directories*), +which serve only as containers of *files*, in which data is actually stored. +While *directories* are fully transparent to both system and user (they can be created, browser, listed and viewed by both), +*files* are, from the system perspective, mostly opaque and inert blocks of data. + +Some metadata, such as file size and access permissions, is associated with each file, +but notably the type of data is generally not actually stored in the filesystem, +but determined loosely based on multiple heuristics depending on the system and context. +Some notable mechanism are: + + +- Suffixes in the name are often used to indicate what kind of data a file should contain. However there is no standardization +- over this, and often a suffix is used for multiple incompatible versions of a file-format. +- Many file-formats specify a specific data-pattern either at the very beginning or very end of a given file. + On unix systems the `libmagic` database and library of these so-called *magic constants* is commonly used to guess + the file-type based on these fragments of data. +- on UNIX systems, files to be executed are checked by a variety of methods + in order to determine which format would fit. For example, script files, the "shebang" symbol, `#!`, can + be used to specify the program that should parse this file in the first line of the file. + +It should be clear already from this short list that to mainstream operating systems, as well as the applications +running on them, the format of a file is almost completely unknown and at best educated guesses can be made. + +Because these various mechanisms are applied at different times by the operating system and applications, +it is possible for files to be labelled as or considered as being in different formats at the same time by different components of the system. +
+The difference between changing a file extension and converting a file between two formats is commonly unclear to users, +for example: see +Why is it possible to convert a file just by renaming it?, https://askubuntu.com/q/166602 + from 2019-12-18 +
+This leads to confusion about the factual format of data among users, but can also pose a serious security risk: +Under some circumstances it is possible that a file contains maliciously-crafted code and is treated as an executable +by one software component, while a security mechanism meant to detect such code determines the same file to be a +legitimate image (the file may in fact be valid in both formats). + +In mmmfs, the example above might look like this instead: +schematic view of an example mmmfs tree + +Superficially, this may look quite similar: there is still only two types of nodes (referred to as *fileders* and *facets*), +and again one of them, the *fileders* are used only to hierarchically organize *facets*. +Unlike *files*, *factes* don't only store a freeform *name*, there is also a dedicated *type* field associated with every *facet*, +that is explicitly designed to be understood and used by the system. + +Despite the similarities, the semantics of this system are very different: +In mainstream filesystems, each *file* stands for itself only; +i.e. in a *directory*, no relationship between *files* is assumed by default, +and files are most of the time read or used outside of the context they exist in in the filesystem. + +In mmmfs, a *facet* should only ever be considered an aspect of its *fileder*, and never as separate from it. +A *fileder* can contain multiple *facets*, but they are meant to be alternate or equivalent representations of the *fileder* itself. +Though for some uses it is required, software in general does not have to be directly aware of the *facets* existing within a *fileder*, +rather it assumes the presence of content in the representation that it requires, and simple requests it. +The *Type Coercion Engine* (see below) will then attempt to satisfy this request based on the *facets* that are in fact present. + +Semantically a *fileder*, like a *directory*, also encompasses all the other *fileders* nested within it (recursively). +Since *fileders* are the primary unit of data to be operated upon, *fileder* nesting emerges as a natural way of structuring complex data, +both for access by the system and applications, as well as the user themself. + +## the type system & coercion engine +As mentioned above, *facets* store data alongside its *type*, and when applications require data from a *fileder*, +they specify the *type* (or the list of *types*) that they require the type to be in. + +In the current iteration of the type system, types are simple strings of text and loosely based on MIME-types [TOOD: quote RFC?]. +MIME types consist of a major- and minor category, and optionally a 'suffix'. +Here are some common MIME-types that are also used in mmmfs: + +- `text/html` and `text/html+frag` (mmmfs only) +- `text/javascript` +- `image/png` +- `image/jpeg` + +While these types allow some amount of specifity, they fall short of describing their content especially in cases where formats overlap: +Source code is often distributed in `.tar.gz` archive files (directory-trees that are first bundled into an `application/x-tar` archive, +and then compressed into an `application/gzip` archive). +Using either of these two types is either incorrect or insufficient information to properly treat and extract the contained data. + +To mitigate this problem, mmmfs *types* can be nested. This is denoted in mmmfs *type* strings using the `->` symbol, e.g. the mmmfs-types +`application/gzip -> application/tar -> dirtree` and `URL -> image/jpeg` describe a tar-gz-compressed directory tree and the URL linking to a JPEG-picture respectively. + +Depending on the outer type this nesting can mean different things: +for URLs the nested type is expected to be found after fetching the URL with HTTP, +compression formats are expected to contain contents of the nested types, +and executable formats are expected to output data of the nested type. + +It is a lot more important to be able to accurately describe the type of a *facet* in mmmfs than in mainstream operating systems, +because while in the latter types are mostly used only associate an application that will then prompt the user about further steps, +mmmfs uses the *type* to automatically find one or more programs to execute to convert or transform the data stored in a *facet* +into the *type* required by the application. + +This process of *type coercion* uses a database of known *converts*, that can be applied to data. +Every *convert* consists of a description of the input *types* that it can accept, the output *type* it would produce for a given input type, +as well as the code for actually converting a given piece of data. +Simple *converts* may simply consist of a fixed in and output type, +such as for example this *convert* for rendering Markdown-encoded text to a HTML hypertext fragment: + + { + inp: 'text/markdown' + out: 'text/html+frag' + transform: (value, ...) -> + -- implementation stripped for brevity + } + +Other *converts* on the other hand may accept a wide range of input types: + + { + inp: 'URL -> image/.*' + out: 'text/html+frag' + transform: (url) -> img src: url + } + +This convert uses a Lua Pattern to specify that it can accept an URL to any type of image, +and convert it to an HTML fragment. + +By using the pattern substitution syntax provided by the Lua `string.gsub` function, +converts can also make the type they return depend on the input type, as is required often when nested types are unpacked: + + { + inp: 'application/gzip -> (.*)' + out: '%1' + transform: (data) -> + -- implementation stripped for brevity + } + +This *convert* accepts an `application/gzip` *type* wrapping any other *type*, and captures that nested type in a pattern group. +It then uses the substituion syntax to specify that nested type as the output of the conversion. +For an input *type* of `application/gzip -> image/png` this *convert* would therefore generate the type `image/png`. + +To further demonstrate the flexibility using this approach, consider this last example: + + { + inp: 'text/moonscript -> (.*)' + out: 'text/lua -> %1' + transform: (code) -> moonscript.to_lua code + } + +This *convert* transpiles MoonScript source-code into Lua source-code, while keeping the nested type +(in this case the result expected when executing either script) the same. + +In addition to the attributes shown above, every *convert* is also rated with a *cost* value. +The cost value is meant to roughly estimate both the cost (in terms of computing power) of the conversion, +as well as the accuracy or immediacy of the conversion. +For example, resizing an image to a lower size should have a high cost, because the process is computationally expensive, +but also because a smaller image represents the original image to a lesser degree. +Similarily, an URL to a piece of content is a less immediate representation than the content itself, +so the cost of a *convert* that simply generates the URL to a piece of data should be high even if the process is very cheap to compute. + +Cost is defined in this way to make sure that the result of a type-coercion operation reflects the content that was present as accurately as possible. +It is also important to prevent some nonsensical results from occuring, such as displaying a link to content instead of the content itself because +the link requires less steps to create than completely converting the content does. + +*** + +Type coercion is implemented using a general pathfinding algorithm, similar to A*. +First, the set of given *types* is found by selecting all *facets* of the *fileder* that match the *name* given in the query. +The set of given *types* is marked in green in the following example graph. + +From there the algorithm recursively checks whether it can reach other types by applying all matching *converts* to the type +that is cheapest to reach, excluding any types that have already been exhaustively-searched in this way. +All types it finds, that have not yet been inserted into the set of given types are then added to the set, +so that they may be searched as well. + +The algorithm doesn't stop immediately after reaching a type from the result set, +it continues search until it either completely exhausts the result space, +or until all non-exhaustively searched paths are already higher than the maximum allowed path. +This ensures that the optimal path is found, even if a more expensive path is found more quickly initially. + +excerpt of the graph of conversion paths from two starting facets to mmm/dom diff --git a/root/articles/mmmfs/mmmfs/text$markdown.md b/root/articles/mmmfs/mmmfs/text$markdown.md deleted file mode 100644 index 7a682dd..0000000 --- a/root/articles/mmmfs/mmmfs/text$markdown.md +++ /dev/null @@ -1,180 +0,0 @@ -# mmmfs -`mmmfs` seeks to improve on two fronts. - -One of the main driving ideas of the mmmfs is to help data portability and use by making it simpler to inter-operate with different data formats. -This is accomplished using two major components, the *Type System and Coercion Engine* and the *Fileder Unified Data Model* for unified data storage and access. - -## the fileder unified data model -The Fileder Model is the underlying unified data storage model. -Like many data storage models it is based fundamentally on the concept of a hierarchical tree-structure. - -schematic view of an example tree in a mainstream filesystem - -In common filesystems, as pictured, data can be organized hierarchically into *folders* (or *directories*), -which serve only as containers of *files*, in which data is actually stored. -While *directories* are fully transparent to both system and user (they can be created, browser, listed and viewed by both), -*files* are, from the system perspective, mostly opaque and inert blocks of data. - -Some metadata, such as file size and access permissions, is associated with each file, -but notably the type of data is generally not actually stored in the filesystem, -but determined loosely based on multiple heuristics depending on the system and context. -Some notable mechanism are: - - -- Suffixes in the name are often used to indicate what kind of data a file should contain. However there is no standardization -- over this, and often a suffix is used for multiple incompatible versions of a file-format. -- Many file-formats specify a specific data-pattern either at the very beginning or very end of a given file. - On unix systems the `libmagic` database and library of these so-called *magic constants* is commonly used to guess - the file-type based on these fragments of data. -- on UNIX systems, files to be executed are checked by a variety of methods - in order to determine which format would fit. For example, script files, the "shebang" symbol, `#!`, can - be used to specify the program that should parse this file in the first line of the file. - -It should be clear already from this short list that to mainstream operating systems, as well as the applications -running on them, the format of a file is almost completely unknown and at best educated guesses can be made. - -Because these various mechanisms are applied at different times by the operating system and applications, -it is possible for files to be labelled as or considered as being in different formats at the same time by different components of the system. -
-The difference between changing a file extension and converting a file between two formats is commonly unclear to users, -for example: see -Why is it possible to convert a file just by renaming it?, https://askubuntu.com/q/166602 - from 2019-12-18 -
-This leads to confusion about the factual format of data among users, but can also pose a serious security risk: -Under some circumstances it is possible that a file contains maliciously-crafted code and is treated as an executable -by one software component, while a security mechanism meant to detect such code determines the same file to be a -legitimate image (the file may in fact be valid in both formats). - -In mmmfs, the example above might look like this instead: -schematic view of an example mmmfs tree - -Superficially, this may look quite similar: there is still only two types of nodes (referred to as *fileders* and *facets*), -and again one of them, the *fileders* are used only to hierarchically organize *facets*. -Unlike *files*, *factes* don't only store a freeform *name*, there is also a dedicated *type* field associated with every *facet*, -that is explicitly designed to be understood and used by the system. - -Despite the similarities, the semantics of this system are very different: -In mainstream filesystems, each *file* stands for itself only; -i.e. in a *directory*, no relationship between *files* is assumed by default, -and files are most of the time read or used outside of the context they exist in in the filesystem. - -In mmmfs, a *facet* should only ever be considered an aspect of its *fileder*, and never as separate from it. -A *fileder* can contain multiple *facets*, but they are meant to be alternate or equivalent representations of the *fileder* itself. -Though for some uses it is required, software in general does not have to be directly aware of the *facets* existing within a *fileder*, -rather it assumes the presence of content in the representation that it requires, and simple requests it. -The *Type Coercion Engine* (see below) will then attempt to satisfy this request based on the *facets* that are in fact present. - -Semantically a *fileder*, like a *directory*, also encompasses all the other *fileders* nested within it (recursively). -Since *fileders* are the primary unit of data to be operated upon, *fileder* nesting emerges as a natural way of structuring complex data, -both for access by the system and applications, as well as the user themself. - -## the type system & coercion engine -As mentioned above, *facets* store data alongside its *type*, and when applications require data from a *fileder*, -they specify the *type* (or the list of *types*) that they require the type to be in. - -In the current iteration of the type system, types are simple strings of text and loosely based on MIME-types [TOOD: quote RFC?]. -MIME types consist of a major- and minor category, and optionally a 'suffix'. -Here are some common MIME-types that are also used in mmmfs: - -- `text/html` and `text/html+frag` (mmmfs only) -- `text/javascript` -- `image/png` -- `image/jpeg` - -While these types allow some amount of specifity, they fall short of describing their content especially in cases where formats overlap: -Source code is often distributed in `.tar.gz` archive files (directory-trees that are first bundled into an `application/x-tar` archive, -and then compressed into an `application/gzip` archive). -Using either of these two types is either incorrect or insufficient information to properly treat and extract the contained data. - -To mitigate this problem, mmmfs *types* can be nested. This is denoted in mmmfs *type* strings using the `->` symbol, e.g. the mmmfs-types -`application/gzip -> application/tar -> dirtree` and `URL -> image/jpeg` describe a tar-gz-compressed directory tree and the URL linking to a JPEG-picture respectively. - -Depending on the outer type this nesting can mean different things: -for URLs the nested type is expected to be found after fetching the URL with HTTP, -compression formats are expected to contain contents of the nested types, -and executable formats are expected to output data of the nested type. - -It is a lot more important to be able to accurately describe the type of a *facet* in mmmfs than in mainstream operating systems, -because while in the latter types are mostly used only associate an application that will then prompt the user about further steps, -mmmfs uses the *type* to automatically find one or more programs to execute to convert or transform the data stored in a *facet* -into the *type* required by the application. - -This process of *type coercion* uses a database of known *converts*, that can be applied to data. -Every *convert* consists of a description of the input *types* that it can accept, the output *type* it would produce for a given input type, -as well as the code for actually converting a given piece of data. -Simple *converts* may simply consist of a fixed in and output type, -such as for example this *convert* for rendering Markdown-encoded text to a HTML hypertext fragment: - - { - inp: 'text/markdown' - out: 'text/html+frag' - transform: (value, ...) -> - -- implementation stripped for brevity - } - -Other *converts* on the other hand may accept a wide range of input types: - - { - inp: 'URL -> image/.*' - out: 'text/html+frag' - transform: (url) -> img src: url - } - -This convert uses a Lua Pattern to specify that it can accept an URL to any type of image, -and convert it to an HTML fragment. - -By using the pattern substitution syntax provided by the Lua `string.gsub` function, -converts can also make the type they return depend on the input type, as is required often when nested types are unpacked: - - { - inp: 'application/gzip -> (.*)' - out: '%1' - transform: (data) -> - -- implementation stripped for brevity - } - -This *convert* accepts an `application/gzip` *type* wrapping any other *type*, and captures that nested type in a pattern group. -It then uses the substituion syntax to specify that nested type as the output of the conversion. -For an input *type* of `application/gzip -> image/png` this *convert* would therefore generate the type `image/png`. - -To further demonstrate the flexibility using this approach, consider this last example: - - { - inp: 'text/moonscript -> (.*)' - out: 'text/lua -> %1' - transform: (code) -> moonscript.to_lua code - } - -This *convert* transpiles MoonScript source-code into Lua source-code, while keeping the nested type -(in this case the result expected when executing either script) the same. - -In addition to the attributes shown above, every *convert* is also rated with a *cost* value. -The cost value is meant to roughly estimate both the cost (in terms of computing power) of the conversion, -as well as the accuracy or immediacy of the conversion. -For example, resizing an image to a lower size should have a high cost, because the process is computationally expensive, -but also because a smaller image represents the original image to a lesser degree. -Similarily, an URL to a piece of content is a less immediate representation than the content itself, -so the cost of a *convert* that simply generates the URL to a piece of data should be high even if the process is very cheap to compute. - -Cost is defined in this way to make sure that the result of a type-coercion operation reflects the content that was present as accurately as possible. -It is also important to prevent some nonsensical results from occuring, such as displaying a link to content instead of the content itself because -the link requires less steps to create than completely converting the content does. - -*** - -Type coercion is implemented using a general pathfinding algorithm, similar to A*. -First, the set of given *types* is found by selecting all *facets* of the *fileder* that match the *name* given in the query. -The set of given *types* is marked in green in the following example graph. - -From there the algorithm recursively checks whether it can reach other types by applying all matching *converts* to the type -that is cheapest to reach, excluding any types that have already been exhaustively-searched in this way. -All types it finds, that have not yet been inserted into the set of given types are then added to the set, -so that they may be searched as well. - -The algorithm doesn't stop immediately after reaching a type from the result set, -it continues search until it either completely exhausts the result space, -or until all non-exhaustively searched paths are already higher than the maximum allowed path. -This ensures that the optimal path is found, even if a more expensive path is found more quickly initially. - -excerpt of the graph of conversion paths from two starting facets to mmm/dom diff --git a/root/articles/mmmfs/problem-statement/text$markdown+sidenotes.md b/root/articles/mmmfs/problem-statement/text$markdown+sidenotes.md new file mode 100644 index 0000000..4723f01 --- /dev/null +++ b/root/articles/mmmfs/problem-statement/text$markdown+sidenotes.md @@ -0,0 +1,128 @@ +# motivation + +The majority of users interacts with modern computing systems in the form of smartphones, laptops or desktop PCs, +using the mainstream operating systems Apple iOS and Mac OS X, Microsoft Windows or Android. + +All of these operating systems share the concept of *Applications* (or *Apps*) as one of the core pieces of their interaction model. +Functionality and capabilities of the digital devices are bundled in, marketed, sold and distributed as *Applications*. + +In addition, a lot of functionality is nowadays delivered in the form of *Web Apps*, which are used inside a *Browser* (which is an *Application* itself). +*Web Apps* often offer similar functionality to other *Applications*, but are subject to some limitations: +In most cases, they are only accessible or functional in the presence of a stable internet connection, +and they have very limited access to the resources of the physical computer they are running on. +For example, they usually cannot interact directly with the file system, hardware peripherals or other applications, +other than through a standardized set of interactions (e.g. selecting a file via a visual menu, capturing audio and video from a webcam, opening another website). + +On the two Desktop Operating Systems (Mac OS X and Windows), file management and the concepts of *Documents* are still central +elements of interactions with the system. The two prevalent smartphone systems deemphasize this concept by only allowing access to the +data actually stored on the device through an app itself. + +This focus on *Applications* as the primary unit of systems can be seen as the root cause of multiple problems: +Because applications are the products companies produce, and software represents a market of users, +developers compete on features integrated into their applications. + +However this lack of control over data access is not the only problem the application-centric approach induces: +A consequence of this is that interoperability between applications and data formats is rare. +To stay relevant, monlithic software or software suites are designed to +As a result applications tend to accrete features rather then modularise and delegate to other software [P Chiusano]. +Because applications are incentivised to keep customers, they make use of network effects to keep customers locked-in. +This often means re-implementing services and functinality that is already available +and integrating it directly in other applications produced by the same organisation. + +This leads to massively complex file formats, +such as for example the .docx format commonly used for storing mostly +textual data enriched with images and videos on occasion. +The docx format is in fact an archive that can contain many virtual files internally, +such as the images and videos referenced before. +However this is completely unknown to the operating system, +and so users are unable to access the contents in this way. +As a result, editing an image contained in a word document is far from a trivial task: +first the document has to be opened in a word processing application, +then the image has to be exported from it and saved in its own, temporary file. +This file can then be edited and saved back to disk. +Once updated, the image may be reimported into the .docx document. +If the word-processing application supports this, +the old image may be replaced directly, otherwise the user may have to remove the old image, +insert the new one and carefully ensure that the positioning in the document remains intact. + +https://www.theverge.com/2019/10/7/20904030/adobe-venezuela-photoshop-behance-us-sanctions + + +The application-centric computing paradigm common today is harmful to users, +because it leaves behind "intert" data as D. Cragg calls it: + +[Cragg 2016] +D. Cragg coins the term "inert data" for the data created, and left behind, by apps and applications in the computing model that is currently prevalent: +Most data today is either intrinsically linked to one specific application, that controls and limits access to the actual information, +or even worse, stored in the cloud where users have no direct access at all and depend soley on online tools that require a stable network connection +and a modern browser, and that could be modified, removed or otherwise negatively impacted at any moment. + +This issue is worsened by the fact that the a lot of software we use today is deployed through the cloud computing and SaaS paradigms, +which are far less reliable than earlier means of distributing software: +Software that runs in the cloud is subject to outages due to network problems, +pricing or availability changes etc. at the whim of the company providing it, as well as ISPs involved in the distribution. +Cloud software, as well as subscription-model software with online-verification mechanisms are additionally subject +to license changes, updates modifiying, restricting or simply removing past functionality etc. +Additionally, many cloud software solutions and ecosystems store the users' data in the cloud, +where they are subject to foreign laws and privacy concerns are intransparently handled by the companies. +Should the company, for any reason, be unable or unwanting to continue servicing a customer, +the data may be irrecoverably lost (or access prevented). + +Data rarely really fits the metaphora of files very well, +and even when it does it is rarely exposed to the user that way: +The 'Contacts' app on a mobile phone or laptop for example does not store each contacts's information +in a separate 'file' (as the metaphora may have initially suggested), +but rather keeps this database hidden away from the user. +Consequently, access to the information contained in the database is only enabled through the contacts applications GUI. + +-- + +According to some researchers in the field of Human-Computer-Interaction, the state of computing is rather dire. + +It seems that a huge majority of daily computer users have silently accepted +that real control over their most important everyday tool will be forever out of reach, +and surrendered it to the relatively small group of 'programmers' curating their experience. + +- Applications are bad +- Services are worse + + +Chiusano blames these issues on the metaphor of the *machine*, and likens apps and applications to appliances. +According to him, what should really be provided are *tools*: +composable pieces of software that naturally lend themselves to, or outrightly call for, +integration into the users' other systems and customization, +rather than lure into the walled-gardens of corporate ecosystems using network-effects. + +Data is inert [Cragg 2016] + +Key points: +- data ownership + data needs to be freely accessible (without depending on a 3rd party) and unconditionally accessible +- data compatibility + data needs to be usable outside the context of it's past use (in the worst case) +- functionality + user needs many, complex needs met + + +Today, computer users are losing more and more control over their data. Between web and cloud +applications holding customer data hostage for providing the services, unappealing and limited mobile file +browsing experiences and the non-interoperable, proprietary file formats holding on to their own data has +become infeasible for many users. mmmfs is an attempt at rethinking file-systems and the computer user +experience to give control back to and empower users. + +mmmfs tries to provide a filesystem that is powerful enough to let you use it as your canvas for thinking, +and working at the computer. mmmfs is made for more than just storing information. Files in mmmfs can interact +and morph to create complex behaviours. + +Let us take as an example the simple task of collecting and arranging a mixed collection of images, videos +and texts in order to brainstorm. To create an assemblage of pictures and text, many might be tempted to open an +Application like Microsoft Word or Adobe Photoshop and create a new document there. Both photoshop files and +word documents are capable of containing texts and images, but when the files are saved, direct access to the +contained data is lost. It is for example a non-trivial and unenjoyable task to edit an image file contained +in a word document in another application and have the changes apply to the document. In the same way, +text contained in a photoshop document cannot be edited in a text editor of your choice. + +Creative use of computer technology is limited to programmers, since applications constrain their users to the +paths and abilities that the developers anticipated and deemed useful. +Note that 'creative' here does not only encompass 'artistic': this applies to any field and means +that innovative use of technology is unlikely to happen as a result of practice by domain experts. diff --git a/root/articles/mmmfs/problem-statement/text$markdown.md b/root/articles/mmmfs/problem-statement/text$markdown.md deleted file mode 100644 index 4723f01..0000000 --- a/root/articles/mmmfs/problem-statement/text$markdown.md +++ /dev/null @@ -1,128 +0,0 @@ -# motivation - -The majority of users interacts with modern computing systems in the form of smartphones, laptops or desktop PCs, -using the mainstream operating systems Apple iOS and Mac OS X, Microsoft Windows or Android. - -All of these operating systems share the concept of *Applications* (or *Apps*) as one of the core pieces of their interaction model. -Functionality and capabilities of the digital devices are bundled in, marketed, sold and distributed as *Applications*. - -In addition, a lot of functionality is nowadays delivered in the form of *Web Apps*, which are used inside a *Browser* (which is an *Application* itself). -*Web Apps* often offer similar functionality to other *Applications*, but are subject to some limitations: -In most cases, they are only accessible or functional in the presence of a stable internet connection, -and they have very limited access to the resources of the physical computer they are running on. -For example, they usually cannot interact directly with the file system, hardware peripherals or other applications, -other than through a standardized set of interactions (e.g. selecting a file via a visual menu, capturing audio and video from a webcam, opening another website). - -On the two Desktop Operating Systems (Mac OS X and Windows), file management and the concepts of *Documents* are still central -elements of interactions with the system. The two prevalent smartphone systems deemphasize this concept by only allowing access to the -data actually stored on the device through an app itself. - -This focus on *Applications* as the primary unit of systems can be seen as the root cause of multiple problems: -Because applications are the products companies produce, and software represents a market of users, -developers compete on features integrated into their applications. - -However this lack of control over data access is not the only problem the application-centric approach induces: -A consequence of this is that interoperability between applications and data formats is rare. -To stay relevant, monlithic software or software suites are designed to -As a result applications tend to accrete features rather then modularise and delegate to other software [P Chiusano]. -Because applications are incentivised to keep customers, they make use of network effects to keep customers locked-in. -This often means re-implementing services and functinality that is already available -and integrating it directly in other applications produced by the same organisation. - -This leads to massively complex file formats, -such as for example the .docx format commonly used for storing mostly -textual data enriched with images and videos on occasion. -The docx format is in fact an archive that can contain many virtual files internally, -such as the images and videos referenced before. -However this is completely unknown to the operating system, -and so users are unable to access the contents in this way. -As a result, editing an image contained in a word document is far from a trivial task: -first the document has to be opened in a word processing application, -then the image has to be exported from it and saved in its own, temporary file. -This file can then be edited and saved back to disk. -Once updated, the image may be reimported into the .docx document. -If the word-processing application supports this, -the old image may be replaced directly, otherwise the user may have to remove the old image, -insert the new one and carefully ensure that the positioning in the document remains intact. - -https://www.theverge.com/2019/10/7/20904030/adobe-venezuela-photoshop-behance-us-sanctions - - -The application-centric computing paradigm common today is harmful to users, -because it leaves behind "intert" data as D. Cragg calls it: - -[Cragg 2016] -D. Cragg coins the term "inert data" for the data created, and left behind, by apps and applications in the computing model that is currently prevalent: -Most data today is either intrinsically linked to one specific application, that controls and limits access to the actual information, -or even worse, stored in the cloud where users have no direct access at all and depend soley on online tools that require a stable network connection -and a modern browser, and that could be modified, removed or otherwise negatively impacted at any moment. - -This issue is worsened by the fact that the a lot of software we use today is deployed through the cloud computing and SaaS paradigms, -which are far less reliable than earlier means of distributing software: -Software that runs in the cloud is subject to outages due to network problems, -pricing or availability changes etc. at the whim of the company providing it, as well as ISPs involved in the distribution. -Cloud software, as well as subscription-model software with online-verification mechanisms are additionally subject -to license changes, updates modifiying, restricting or simply removing past functionality etc. -Additionally, many cloud software solutions and ecosystems store the users' data in the cloud, -where they are subject to foreign laws and privacy concerns are intransparently handled by the companies. -Should the company, for any reason, be unable or unwanting to continue servicing a customer, -the data may be irrecoverably lost (or access prevented). - -Data rarely really fits the metaphora of files very well, -and even when it does it is rarely exposed to the user that way: -The 'Contacts' app on a mobile phone or laptop for example does not store each contacts's information -in a separate 'file' (as the metaphora may have initially suggested), -but rather keeps this database hidden away from the user. -Consequently, access to the information contained in the database is only enabled through the contacts applications GUI. - --- - -According to some researchers in the field of Human-Computer-Interaction, the state of computing is rather dire. - -It seems that a huge majority of daily computer users have silently accepted -that real control over their most important everyday tool will be forever out of reach, -and surrendered it to the relatively small group of 'programmers' curating their experience. - -- Applications are bad -- Services are worse - - -Chiusano blames these issues on the metaphor of the *machine*, and likens apps and applications to appliances. -According to him, what should really be provided are *tools*: -composable pieces of software that naturally lend themselves to, or outrightly call for, -integration into the users' other systems and customization, -rather than lure into the walled-gardens of corporate ecosystems using network-effects. - -Data is inert [Cragg 2016] - -Key points: -- data ownership - data needs to be freely accessible (without depending on a 3rd party) and unconditionally accessible -- data compatibility - data needs to be usable outside the context of it's past use (in the worst case) -- functionality - user needs many, complex needs met - - -Today, computer users are losing more and more control over their data. Between web and cloud -applications holding customer data hostage for providing the services, unappealing and limited mobile file -browsing experiences and the non-interoperable, proprietary file formats holding on to their own data has -become infeasible for many users. mmmfs is an attempt at rethinking file-systems and the computer user -experience to give control back to and empower users. - -mmmfs tries to provide a filesystem that is powerful enough to let you use it as your canvas for thinking, -and working at the computer. mmmfs is made for more than just storing information. Files in mmmfs can interact -and morph to create complex behaviours. - -Let us take as an example the simple task of collecting and arranging a mixed collection of images, videos -and texts in order to brainstorm. To create an assemblage of pictures and text, many might be tempted to open an -Application like Microsoft Word or Adobe Photoshop and create a new document there. Both photoshop files and -word documents are capable of containing texts and images, but when the files are saved, direct access to the -contained data is lost. It is for example a non-trivial and unenjoyable task to edit an image file contained -in a word document in another application and have the changes apply to the document. In the same way, -text contained in a photoshop document cannot be edited in a text editor of your choice. - -Creative use of computer technology is limited to programmers, since applications constrain their users to the -paths and abilities that the developers anticipated and deemed useful. -Note that 'creative' here does not only encompass 'artistic': this applies to any field and means -that innovative use of technology is unlikely to happen as a result of practice by domain experts. -- cgit v1.2.3 From 565fea25c05c51f6e3d5940a55bc0c61423acc20 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 20 Dec 2019 15:27:46 +0100 Subject: fix relative mmm-require/link with multiple .. --- mmm/mmmfs/util.moon | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/mmm/mmmfs/util.moon b/mmm/mmmfs/util.moon index 8887187..1ba5697 100644 --- a/mmm/mmmfs/util.moon +++ b/mmm/mmmfs/util.moon @@ -18,28 +18,15 @@ tourl = (path) -> assert origin, "cannot resolve relative path '#{fileder}' without origin!" fileder = "#{origin.path}/#{fileder}" - fileder = fileder\gsub '/([^/]-)/%.%./', '/' + while fileder\match '/([^/]-)/%.%./' + fileder = fileder\gsub '/([^/]-)/%.%./', '/' + if origin.path == fileder\sub 1, #origin.path assert (origin\walk fileder), "couldn't resolve path '#{fileder}' from #{origin}" else assert BROWSER and BROWSER.root, "cannot resolve absolute path '#{fileder}' without BROWSER and root set!" assert (BROWSER.root\walk fileder), "couldn't resolve path '#{fileder}'" - -- if 'string' == type fileder - -- if '/' == fileder\sub 1, 1 - -- fileder = fileder\gsub '/([^/]-)/%.%./', '/' - -- assert BROWSER and BROWSER.root, "cannot resolve absolute path '#{fileder}' without BROWSER and root set!" - -- assert (BROWSER.root\walk fileder), "couldn't resolve path '#{fileder}'" - -- else - -- assert origin, "cannot resolve relative path '#{fileder}' without origin!" - -- fileder = "#{origin.path}/#{fileder}" - -- fileder = fileder\gsub '/([^/]-)/%.%./', '/' - -- if origin.path == fileder\sub 1, #origin.path - -- assert (origin\walk fileder), "couldn't resolve path '#{fileder}' from #{origin}" - -- else - -- assert BROWSER and BROWSER.root, "cannot resolve absolute path '#{fileder}' without BROWSER and root set!" - -- assert (BROWSER.root\walk fileder), "couldn't resolve path '#{fileder}'" - else assert fileder, "no fileder passed." -- cgit v1.2.3 From 4d5d48eac55f38749420ad29ad2e0ff2d35fe438 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 20 Dec 2019 15:28:41 +0100 Subject: add ba_log 2019-12-20 --- root/articles/mmmfs/ba_log/$order | 1 + .../ba_log/2019-12-20/text$markdown+sidenotes.md | 39 ++++++++++++++++++++++ ...down: text$moonscript -> fn -> text$markdown.md | 1 + 3 files changed, 41 insertions(+) create mode 100644 root/articles/mmmfs/ba_log/2019-12-20/text$markdown+sidenotes.md create mode 100644 root/articles/mmmfs/references/inkandswitch/markdown: text$moonscript -> fn -> text$markdown.md diff --git a/root/articles/mmmfs/ba_log/$order b/root/articles/mmmfs/ba_log/$order index 564679b..dabdaee 100644 --- a/root/articles/mmmfs/ba_log/$order +++ b/root/articles/mmmfs/ba_log/$order @@ -11,3 +11,4 @@ 2019-10-29 2019-11-01 2019-11-25 +2019-12-20 diff --git a/root/articles/mmmfs/ba_log/2019-12-20/text$markdown+sidenotes.md b/root/articles/mmmfs/ba_log/2019-12-20/text$markdown+sidenotes.md new file mode 100644 index 0000000..7d592a0 --- /dev/null +++ b/root/articles/mmmfs/ba_log/2019-12-20/text$markdown+sidenotes.md @@ -0,0 +1,39 @@ +In the last three days I have been working extensively on support for sidenotes and academic referencing, +inspired by Edward Tufte's style of publishing (as seen in *Beatiful Evidence* and documented in [tufte-css][tufte-css]. + +To this end margin-notes have been implemented in the CSS styling of the page using two classes, `sidenote` and +`sidenote-container`, which are to be applied to individual sidenotes and the containing document respectively. +Sidenotes are then pulled out of their surrounding context using `position: absolute` and placed in a margin that is +left free by `sidenote-container`. + +Inside of markdown files, sidenotes can then be added simply using basic HTML, like so: + +```md +
additional information to be found on the margin
+An example paragraph of text, describing something. +``` + +Which will render like this: + +>
additional information to be found on the margin
+> An example paragraph of text, describing something. + +Additionally, conversions from `text/bibtex`, a reference specification format, to `mmm/dom` have been added, that +create citations using the metadata available in the BibTeX file. + +For example the following BibTeX is rendered like this: + + + +> + +I also added a special override that links to +BibTeX files by placing the citation in a sidenote, and adding a footnote indicator in-text. + +There is also a handy convert that turns ACM Digital Library links into URLs that directly return the BibTeX file, +which allows me to cite the links directly without manually adding the BibTeX information to my document. + +All of this is implemented in the `cites` plug-in: [`cites.moon`][cites.moon]. + +[cites.moon]: https://git.s-ol.nu/mmm/blob/ba/mmm/mmmfs/plugins/cites.moon +[tufte-css]: https://edwardtufte.github.io/tufte-css/ diff --git a/root/articles/mmmfs/references/inkandswitch/markdown: text$moonscript -> fn -> text$markdown.md b/root/articles/mmmfs/references/inkandswitch/markdown: text$moonscript -> fn -> text$markdown.md new file mode 100644 index 0000000..9439841 --- /dev/null +++ b/root/articles/mmmfs/references/inkandswitch/markdown: text$moonscript -> fn -> text$markdown.md @@ -0,0 +1 @@ +=> "```\n" .. (@gett 'text/bibtex') .. "\n```" -- cgit v1.2.3 From aab83d4f51ede07cad4152fa9d7b73db054a5963 Mon Sep 17 00:00:00 2001 From: s-ol Date: Sun, 22 Dec 2019 16:01:47 +0100 Subject: lots more writing --- mmm/mmmfs/plugins/cites.moon | 46 +++++--- root/articles/mmmfs/$order | 4 +- .../mmmfs/abstract/text$markdown+sidenotes.md | 4 + .../print: text$moonscript -> fn -> mmm$dom.moon | 16 +++ .../ba_log/text$moonscript -> fn -> mmm$dom.moon | 4 +- .../mmmfs/conclusion/text$markdown+sidenotes.md | 4 + .../mmmfs/evaluation/text$markdown+sidenotes.md | 9 +- .../examples/text$moonscript -> fn -> mmm$dom.moon | 38 +++--- .../mmmfs/framework/text$markdown+sidenotes.md | 69 +++-------- root/articles/mmmfs/historical-approaches/$order | 1 + .../historical-approaches/star-graph/image$png.png | Bin 0 -> 87351 bytes .../text$markdown+sidenotes.md | 71 ++++++++++++ .../mmmfs/mmmfs/text$markdown+sidenotes.md | 28 +++-- .../mmmfs/motivation/text$markdown+sidenotes.md | 120 +++++++++++++++++++ .../print: text$moonscript -> fn -> mmm$dom.moon | 51 ++++++++ .../problem-statement/text$markdown+sidenotes.md | 128 --------------------- root/articles/mmmfs/references/$order | 3 + .../mmmfs/references/aspect-ratios/text$bibtex | 2 +- .../mmmfs/references/hypercard/text$bibtex | 6 + .../mmmfs/references/linux-exec/text$bibtex | 2 +- root/articles/mmmfs/references/memex/text$bibtex | 8 ++ .../mmmfs/references/poc-or-gtfo/text$bibtex | 4 +- .../text$moonscript -> fn -> mmm$dom.moon | 9 +- .../mmmfs/references/wikipedia/text$bibtex | 6 + .../mmmfs/references/xerox-star/text$bibtex | 17 +++ 25 files changed, 411 insertions(+), 239 deletions(-) create mode 100644 root/articles/mmmfs/ba_log/print: text$moonscript -> fn -> mmm$dom.moon create mode 100644 root/articles/mmmfs/conclusion/text$markdown+sidenotes.md create mode 100644 root/articles/mmmfs/historical-approaches/$order create mode 100644 root/articles/mmmfs/historical-approaches/star-graph/image$png.png create mode 100644 root/articles/mmmfs/historical-approaches/text$markdown+sidenotes.md create mode 100644 root/articles/mmmfs/motivation/text$markdown+sidenotes.md create mode 100644 root/articles/mmmfs/print: text$moonscript -> fn -> mmm$dom.moon delete mode 100644 root/articles/mmmfs/problem-statement/text$markdown+sidenotes.md create mode 100644 root/articles/mmmfs/references/hypercard/text$bibtex create mode 100644 root/articles/mmmfs/references/memex/text$bibtex create mode 100644 root/articles/mmmfs/references/wikipedia/text$bibtex create mode 100644 root/articles/mmmfs/references/xerox-star/text$bibtex diff --git a/mmm/mmmfs/plugins/cites.moon b/mmm/mmmfs/plugins/cites.moon index 04e809d..d367c36 100644 --- a/mmm/mmmfs/plugins/cites.moon +++ b/mmm/mmmfs/plugins/cites.moon @@ -6,27 +6,41 @@ parse_bibtex = (src) -> for key, val in kv\gmatch '([a-z]-)%s*=%s*{(.-)}' info[key] = val -title = (info) -> - assert info.title, "cite doesn't have title" - inner = i info.title - if info.url - a inner, href: info.url, style: display: 'inline' +title = () => + assert @title, "cite doesn't have title" + inner = i @title + if @url + a inner, href: @url, style: display: 'inline' else b inner -format_full = (info) -> - tt = title info - dot, com = if info.title\match '[.?!]$' then '', '' else '.', ',' - switch info._type +format_full = () => + tt = title @ + dot, com = if @title\match '[.?!]$' then '', '' else '.', ',' + switch @_type when 'book', 'article' - span "#{info.author} (#{info.year}), ", tt, "#{dot} #{info.publisher}" - when 'web' - -- note = if info.note then ", #{info.note}" else '' - visited = if info.visited then " from #{info.visited}" else "" - span tt, "#{com} #{info.url}#{visited}" + span with setmetatable {}, __index: table + \insert "#{@author} (#{@year}), " + \insert tt + if @journal + \insert "#{dot} " + \insert i @journal + \insert ", volume #{@volume}" if @volume + \insert ", pages #{@pages}" if @pages + \insert "#{dot} #{@publisher}" if @publisher + when 'web', 'online' + span with setmetatable {}, __index: table + \insert "#{@author} (#{@year}), " if @author and @year + \insert tt + \insert " (#{@year})" if @year and not @author + \insert "#{com} #{@url}" + \insert " from #{@visited}" if @visited else - span "#{info.author} (#{info.year}), ", tt, "#{dot} #{info.publisher}" - + span with setmetatable {}, __index: table + \insert "#{@author} (#{@year}), " + \insert tt + \insert "#{dot} #{@publisher}" if @publisher + span tbl { converts: { { diff --git a/root/articles/mmmfs/$order b/root/articles/mmmfs/$order index 6707527..dd9746b 100644 --- a/root/articles/mmmfs/$order +++ b/root/articles/mmmfs/$order @@ -1,8 +1,10 @@ abstract -problem-statement +motivation +historical-approaches framework mmmfs examples evaluation +conclusion references ba_log diff --git a/root/articles/mmmfs/abstract/text$markdown+sidenotes.md b/root/articles/mmmfs/abstract/text$markdown+sidenotes.md index e69de29..9ac0894 100644 --- a/root/articles/mmmfs/abstract/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/abstract/text$markdown+sidenotes.md @@ -0,0 +1,4 @@ +abstract +======== + +[tbd] diff --git a/root/articles/mmmfs/ba_log/print: text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/ba_log/print: text$moonscript -> fn -> mmm$dom.moon new file mode 100644 index 0000000..83c0c2c --- /dev/null +++ b/root/articles/mmmfs/ba_log/print: text$moonscript -> fn -> mmm$dom.moon @@ -0,0 +1,16 @@ +import div, section, h1, h2, hr from require 'mmm.dom' +import link_to from (require 'mmm.mmmfs.util') require 'mmm.dom' +import ropairs from require 'mmm.ordered' + +=> + div { + h1 link_to @, "appendix: project log" + table.unpack for post in *@children + continue if post\get 'hidden: bool' + + section { + hr! + h2 link_to post, post\gett 'name: mmm/dom' + (post\gett 'mmm/dom') + } + } diff --git a/root/articles/mmmfs/ba_log/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/ba_log/text$moonscript -> fn -> mmm$dom.moon index 1dd0bc3..37ffc78 100644 --- a/root/articles/mmmfs/ba_log/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/ba_log/text$moonscript -> fn -> mmm$dom.moon @@ -1,10 +1,10 @@ -import div, h3, ul, li from require 'mmm.dom' +import div, h1, ul, li from require 'mmm.dom' import link_to from (require 'mmm.mmmfs.util') require 'mmm.dom' import ropairs from require 'mmm.ordered' => div { - h3 link_to @ + h1 link_to @, "appendix: project log" ul do posts = for post in *@children continue if post\get 'hidden: bool' diff --git a/root/articles/mmmfs/conclusion/text$markdown+sidenotes.md b/root/articles/mmmfs/conclusion/text$markdown+sidenotes.md new file mode 100644 index 0000000..de38bec --- /dev/null +++ b/root/articles/mmmfs/conclusion/text$markdown+sidenotes.md @@ -0,0 +1,4 @@ +conclusion +========== + +[tbd] diff --git a/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md b/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md index 773c842..812b0c5 100644 --- a/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md @@ -2,6 +2,9 @@ evaluation ========== ## examples +In this section I will take a look at the implementations of the example for the use cases outlined above, +and evaluate them with regard to the framework derived in the corresponding section above. + ### publishing and blogging Since mmmfs has grown out of the need for a versatile CMS for a personal publishing website, it is not surprising to to see that it is still up to that job. Nevertheless it is worth taking a look at its strengths and weaknesses in this @@ -159,8 +162,8 @@ The content editor is wholly separate from the visible representation, and only fileder can be edited. This means that content cannot be edited in its context, which is particularily annoying due to the fragmentation of content that mmmfs encourages. -As a result, the experiences of interacting with the system at large is still a very different experience than -editing content (and thereby extending the system) in it. This is expected to represent a major hurdle for users -getting started with the system, and is a major shortcoming in enabling end-user programming as set as a goal for +As a result, interacting with the system at large is still a very different experience than editing content (and +thereby extending the system) in it. This is expected to represent a major hurdle for users getting started with the +system, and is a major shortcoming in enabling end-user programming as set as a goal for this project. A future iteration should take care to reconsider how editing can be integrated more holistically with the other core concepts of the design. diff --git a/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon index a553f8d..c79ffcf 100644 --- a/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon @@ -4,7 +4,8 @@ -- resolves to a value of type mmm/dom => html = require 'mmm.dom' - import h4, div, a, span from html + import h4, div, a, span, ul, li from html + import link_to from (require 'mmm.mmmfs.util') html -- render a preview block preview = (child) -> @@ -14,23 +15,26 @@ -- get 'preview' as a DOM description (nil if no value or conversion possible) content = child\get 'preview', 'mmm/dom' - div { - h4 title, style: { margin: 0, cursor: 'pointer' }, onclick: -> BROWSER\navigate child.path - content or span '(no renderable content)', style: { color: 'red' }, - style: { - display: 'inline-block', - width: '300px', - height: '200px', - padding: '4px', - margin: '8px', - border: '4px solid #eeeeee', - overflow: 'hidden', - }, - } + -- div { + -- h4 title, style: { margin: 0, cursor: 'pointer' }, onclick: -> BROWSER\navigate child.path + -- content or span '(no renderable content)', style: { color: 'red' }, + -- style: { + -- display: 'inline-block', + -- width: '300px', + -- height: '200px', + -- padding: '4px', + -- margin: '8px', + -- border: '4px solid #eeeeee', + -- overflow: 'hidden', + -- }, + -- } - content = for child in *@children + li link_to child + + content = ul for child in *@children preview child - table.insert content, 1, (@gett 'intro: mmm/dom') + -- table.insert content, 1, (@gett 'intro: mmm/dom') + -- div content - div content + div (@gett 'intro: mmm/dom'), content diff --git a/root/articles/mmmfs/framework/text$markdown+sidenotes.md b/root/articles/mmmfs/framework/text$markdown+sidenotes.md index af446a5..6fa2d3a 100644 --- a/root/articles/mmmfs/framework/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/framework/text$markdown+sidenotes.md @@ -1,52 +1,13 @@ -Two of the earliest wholistic computing systems, the Xerox Alto and Xerox Star, both developed at Xerox PARC and introduced in the 70s and early 80s, pioneered not only graphical user-interfaces, but also the "Desktop Metaphor". -The desktop metaphor presents information as stored in "Documents" that can be organized in folders and on the "Desktop". It invokes a strong analogy to physical tools. -One of the differences between the Xerox Star system and other systems at the time, as well as the systems we use currently, is that the type of data a file represents is directly known to the system. +evaluation framework +==================== -
+In the following section, I will collect approaches and reviews of different end-user software systems from current +literature, as well as derive and present my own requirements and guiding principles for the development of a new system. -> In a Desktop metaphor system, users deal mainly with data files, oblivious to the existence of programs. -> They do not "invoke a text editor", they "open a document". -> The system knows the type of each file and notifies the relevant application program when one is opened. -> -> The disadvantage of assigning data files to applications is that users sometimes want to operate on a file with a program other than -its "assigned" application. \[...\] -> Star's designers feel that, for its audience, the advantages of allowing users to forget -about programs outweighs this disadvantage. - -Other systems at the time lacked any knowledge of the type of files, -and while mainstream operating systems of today have retro-fit the ability to associate and memorize the preferred applications to use for a given file based on it's name suffix, the intention of making applications a secondary, technical detail of working with the computer has surely been lost. - -Another design detail of the Star system is the concept of "properties" that are stored for "objects" throughout the system (the objects being anything from files to characters or paragraphs). -These typed pieces of information are labelled with a name and persistently stored, providing a mechanism to store metadata such as user preference for ordering or defaut view of a folder for example. - -*** - -Fig. 8 - Star Retrospective - -The earliest indirect influence for the Xerox Alto and many other systems of its time, -was the *Memex*. The *Memex* is a hypothetical device and system for knowledge management. -Proposed by Vannevar Bush in 1945, the concept predates much of the technology that later was used to implement many parts of the vision. In essence, the concept of hypertext was invented. - -*** - -One of the systems that could be said to have come closest to a practical implementation of the Memex might be Apple's *Hypercard*. - -https://archive.org/details/CC501_hypercard - -"So I can have the information in these stacks tied together in a way that makes sense" - -In a demonstration video, the creators of the software showcase a system of stacks of cards that together implement, amongst others, a calendar (with yearly and weekly views), a list of digital business cards for storing phone numbers and addresses, and a todo list. -However these stacks of cards are not just usable by themselves, it is also demonstrated how stacks can link to each other in meaningful ways, such as jumping to the card corresponding to a specific day from the yearly calendar view, or automatically looking up the card corresponding to a person's first name from a mention of the name in the text on a different card. - -Alongside Spreadsheets, *Hypercard* remains one of the most successful implementations of end-user programming, even today. -While it's technical abilities have been long matched and passed by other software (such as the ubiquitous HTML hypertext markup language), these technical successors have failed the legacy of *Hypercard* as an end-user tool: -while it is easier than ever to publish content on the web (through various social media and microblogging services), the benefits of hypermedia as a customizable medium for personal management have nearly vanished. -End-users do not create hypertext anymore. - -The *UNIX Philosophy* -describes the software design paradigm pioneered in the creation of the Unix operating system at the AT&T Bell Labs -research center in the 1960s. The concepts are considered quite influental and are still notably applied in the Linux community. -Many attempts at summaries exist, but the following includes the pieces that are especially relevant even today: +The *UNIX Philosophy* describes the software design paradigm +pioneered in the creation of the Unix operating system at the AT&T Bell Labs research center in the 1960s. The +concepts are considered quite influental and are still notably applied in the Linux community. Many attempts at +summaries exist, but the following includes the pieces that are especially relevant even today: > Even though the UNIX system introduces a number of innovative programs and techniques, no single program or idea makes it work well. > Instead, what makes it effective is the approach to programming, a philosophy of using the computer. Although that philosophy can't be @@ -54,14 +15,12 @@ Many attempts at summaries exist, but the following includes the pieces that are > than from the programs themselves. Many UNIX programs do quite trivial things in isolation, but, combined with other programs, > become general and useful tools. -This approach has multiple benefits with regard to end-user programmability: -Assembling the system out of simple, modular pieces means that for any given task a user may want to implement, -it is very likely that preexisting parts of the system can help the user realize a solution. -Wherever such a preexisting part exists, it pays off designing it in such a way that it is easy to integrate for the user later. -Assembling the system as a collection of modular, interacting pieces also enables future growth and customization, -since pieces may be swapped out with customized or alternate software at any time. - -*** +This approach has multiple benefits with regard to end-user programmability: Assembling the system out of simple, +modular pieces means that for any given task a user may want to implement, it is very likely that preexisting parts +of the system can help the user realize a solution. Wherever such a preexisting part exists, it pays off designing it +in such a way that it is easy to integrate for the user later. Assembling the system as a collection of modular, +interacting pieces also enables future growth and customization, since pieces may be swapped out with customized or +alternate software at any time. Based on this, a modern data storage and processing ecosystem should enable transclusion of both content and behaviours between contexts. diff --git a/root/articles/mmmfs/historical-approaches/$order b/root/articles/mmmfs/historical-approaches/$order new file mode 100644 index 0000000..b98a91b --- /dev/null +++ b/root/articles/mmmfs/historical-approaches/$order @@ -0,0 +1 @@ +star-graph diff --git a/root/articles/mmmfs/historical-approaches/star-graph/image$png.png b/root/articles/mmmfs/historical-approaches/star-graph/image$png.png new file mode 100644 index 0000000..ed4003c Binary files /dev/null and b/root/articles/mmmfs/historical-approaches/star-graph/image$png.png differ diff --git a/root/articles/mmmfs/historical-approaches/text$markdown+sidenotes.md b/root/articles/mmmfs/historical-approaches/text$markdown+sidenotes.md new file mode 100644 index 0000000..ebbe51c --- /dev/null +++ b/root/articles/mmmfs/historical-approaches/text$markdown+sidenotes.md @@ -0,0 +1,71 @@ +historical approaches +===================== + +Two of the earliest wholistic computing systems, the Xerox Alto and Xerox Star, both developed at Xerox PARC and +introduced in the 70s and early 80s, pioneered not only graphical user-interfaces, but also the "Desktop Metaphor". +The desktop metaphor presents information as stored in "Documents" that can be organized in folders and on the +"Desktop". It invokes a strong analogy to physical tools. One of the differences between the Xerox Star system and +other systems at the time, as well as the systems we use currently, is that the type of data a file represents is +directly known to the system. + +In a retrospective analysis of the Xerox Star's impact on the computer +industry, the desktop metaphor is described as follows: + +> In a Desktop metaphor system, users deal mainly with data files, oblivious to the existence of programs. +> They do not "invoke a text editor", they "open a document". +> The system knows the type of each file and notifies the relevant application program when one is opened. +> +> The disadvantage of assigning data files to applications is that users sometimes want to operate on a file with a +> program other than its "assigned" application. \[...\] +> Star's designers feel that, for its audience, the advantages of allowing users to forget about programs outweighs +> this disadvantage. + +Other systems at the time lacked any knowledge of the type of files, and while mainstream operating systems of today +have retro-fit the ability to associate and memorize the preferred applications to use for a given file based on it's +name suffix, the intention of making applications a secondary, technical detail of working with the computer has +surely been lost. + +Another design detail of the Star system is the concept of "properties" that are stored for "objects" throughout the +system (the objects being anything from files to characters or paragraphs). These typed pieces of information are +labelled with a name and persistently stored, providing a mechanism to store metadata such as user preference for +ordering or the defaut view mode of a folder for example. + +
+

How systems influenced later systems. This graph summarizes how various systems related to Star have influenced +one another over the years. Time progresses downwards. Double arrows indicate direct successors (i.e., +follow-on versions). [...]

+
+ + +The earliest indirect influence for the Xerox Alto and many other systems of its time, was the *Memex*. +The *Memex* is a hypothetical device and system for knowledge management. Proposed by Vannevar Bush in 1945, the concept predates much of the technology that later was used to implement +many parts of the vision. + +While the article extrapolates from existing technology at the time, describing at times +very concrete machinery based on microfilm and mechanical contraptions, many of the conceptual predictions became +true or inspired .... + +One of the most innovative elements of Bush's predictions is the idea of technologically cross-referenced and +connected information, which would later be known and created as *hypertext*. While hypertext powers the majority of +today's internet, many of the advantages that Bush imagined have not carried over into the personal use of computers. +There are very few tools for creating personal, highly-interconnected knowledgebases, even though this is technically +feasible, and a proven concept (exemplified for example by the massively successful online encyclopedia *Wikipedia*). + +While there are little such tools available today, one of the systems that could be said to have come closest to a +practical implementation of such a Memex-inspired system for personal use might be Apple's *HyperCard*. + +In a live demonstration, the creators of the software showcase +a system of stacks of cards that together implement, amongst others, a calendar (with yearly and weekly views), a +list of digital business cards for storing phone numbers and addresses, and a todo list. However these stacks of +cards are not just usable by themselves, it is also demonstrated how stacks can link to each other in meaningful ways, +such as jumping to the card corresponding to a specific day from the yearly calendar view, or automatically looking +up the card corresponding to a person's first name from a mention of the name in the text on a different card. + +Alongside Spreadsheets, *HyperCard* remains one of the most successful implementations of end-user programming, even +today. While it's technical abilities have been long matched and surpassed by other software (such as the ubiquitous +*Hypertext Markup Language*, HTML), these technical successors have failed the legacy of *HyperCard* as an end-user +tool: while it is easier than ever to publish content on the web (through various social media and microblogging +services), the benefits of hypermedia as a customizable medium for personal management have nearly vanished. +End-users do not create hypertext anymore. diff --git a/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md b/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md index 7a682dd..aa09173 100644 --- a/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md @@ -1,8 +1,17 @@ -# mmmfs -`mmmfs` seeks to improve on two fronts. +mmmfs +===== -One of the main driving ideas of the mmmfs is to help data portability and use by making it simpler to inter-operate with different data formats. -This is accomplished using two major components, the *Type System and Coercion Engine* and the *Fileder Unified Data Model* for unified data storage and access. +`mmmfs` is a newly developed personal data storage and processing system. It was developed first as a tool for +generating static websites, but has been extended with live interaction and introspection, as well as embedded +editing capabilities as part of this work. + +mmmfs has been designed with a focus on data ownership for users. One of the main driving ideas is to unlock data +from external data silos and file formats by making data available uniformly across different storage systems and +formats. Secondly, computation and interactive elements are also integrated in the paradigm, so that mmmfs can be +seemlessly extended and molded to the users needs. + +The abstraction of data types is accomplished using two major components, the *Type System and Coercion Engine* and +the *Fileder Unified Data Model* for unified data storage and access. ## the fileder unified data model The Fileder Model is the underlying unified data storage model. @@ -20,7 +29,6 @@ but notably the type of data is generally not actually stored in the filesystem, but determined loosely based on multiple heuristics depending on the system and context. Some notable mechanism are: - - Suffixes in the name are often used to indicate what kind of data a file should contain. However there is no standardization - over this, and often a suffix is used for multiple incompatible versions of a file-format. - Many file-formats specify a specific data-pattern either at the very beginning or very end of a given file. @@ -37,9 +45,9 @@ Because these various mechanisms are applied at different times by the operating it is possible for files to be labelled as or considered as being in different formats at the same time by different components of the system.
The difference between changing a file extension and converting a file between two formats is commonly unclear to users, -for example: see -Why is it possible to convert a file just by renaming it?, https://askubuntu.com/q/166602 - from 2019-12-18 +see for example +Why is it possible to convert a file just by renaming it?, https://askubuntu.com/q/166602 from 2019-12-18 +
This leads to confusion about the factual format of data among users, but can also pose a serious security risk: Under some circumstances it is possible that a file contains maliciously-crafted code and is treated as an executable @@ -161,9 +169,7 @@ Cost is defined in this way to make sure that the result of a type-coercion oper It is also important to prevent some nonsensical results from occuring, such as displaying a link to content instead of the content itself because the link requires less steps to create than completely converting the content does. -*** - -Type coercion is implemented using a general pathfinding algorithm, similar to A*. +Type coercion is implemented using a general pathfinding algorithm, similar to A\*. First, the set of given *types* is found by selecting all *facets* of the *fileder* that match the *name* given in the query. The set of given *types* is marked in green in the following example graph. diff --git a/root/articles/mmmfs/motivation/text$markdown+sidenotes.md b/root/articles/mmmfs/motivation/text$markdown+sidenotes.md new file mode 100644 index 0000000..e178f4a --- /dev/null +++ b/root/articles/mmmfs/motivation/text$markdown+sidenotes.md @@ -0,0 +1,120 @@ +motivation +========== + +The majority of users interacts with modern computing systems in the form of smartphones, laptops or desktop PCs, +using the mainstream operating systems Apple iOS and Mac OS X, Microsoft Windows or Android. + +All of these operating systems share the concept of *Applications* (or *Apps*) as one of the core pieces of their interaction model. +Functionality and capabilities of the digital devices are bundled in, marketed, sold and distributed as *Applications*. + +In addition, a lot of functionality is nowadays delivered in the form of *Web Apps*, which are used inside a *Browser* (which is an *Application* itself). +*Web Apps* often offer similar functionality to other *Applications*, but are subject to some limitations: +In most cases, they are only accessible or functional in the presence of a stable internet connection, +and they have very limited access to the resources of the physical computer they are running on. +For example, they usually cannot interact directly with the file system, hardware peripherals or other applications, +other than through a standardized set of interactions (e.g. selecting a file via a visual menu, capturing audio and video from a webcam, opening another website). + +On the two Desktop Operating Systems (Mac OS X and Windows), file management and the concepts of *Documents* are still central +elements of interactions with the system. The two prevalent smartphone systems deemphasize this concept by only allowing access to the +data actually stored on the device through an app itself. + +This focus on *Applications* as the primary unit of systems can be seen as the root cause of multiple problems: +Because applications are the products companies produce, and software represents a market of users, +developers compete on features integrated into their applications. + +However this lack of control over data access is not the only problem the application-centric approach induces: +A consequence of this is that interoperability between applications and data formats is rare. +To stay relevant, monlithic software or software suites are designed to +As a result applications tend to accrete features rather then modularise and delegate to other software [P Chiusano]. +Because applications are incentivised to keep customers, they make use of network effects to keep customers locked-in. +This often means re-implementing services and functinality that is already available +and integrating it directly in other applications produced by the same organisation. + +This leads to massively complex file formats, +such as for example the .docx format commonly used for storing mostly +textual data enriched with images and videos on occasion. +The docx format is in fact an archive that can contain many virtual files internally, +such as the images and videos referenced before. +However this is completely unknown to the operating system, +and so users are unable to access the contents in this way. +As a result, editing an image contained in a word document is far from a trivial task: +first the document has to be opened in a word processing application, +then the image has to be exported from it and saved in its own, temporary file. +This file can then be edited and saved back to disk. +Once updated, the image may be reimported into the .docx document. +If the word-processing application supports this, +the old image may be replaced directly, otherwise the user may have to remove the old image, +insert the new one and carefully ensure that the positioning in the document remains intact. + +Let us take as an example the simple task of collecting and arranging a mixed collection of images, videos +and texts in order to brainstorm. To create an assemblage of pictures and text, many might be tempted to open an +Application like Microsoft Word or Adobe Photoshop and create a new document there. Both photoshop files and +word documents are capable of containing texts and images, but when the files are saved, direct access to the +contained data is lost. It is for example a non-trivial and unenjoyable task to edit an image file contained +in a word document in another application and have the changes apply to the document. In the same way, +text contained in a photoshop document cannot be edited in a text editor of your choice. + + +https://www.theverge.com/2019/10/7/20904030/adobe-venezuela-photoshop-behance-us-sanctions + + +The application-centric computing paradigm common today is harmful to users, +because it leaves behind "inert" data, as D. Cragg calls it: + +[Cragg 2016] +D. Cragg coins the term "inert data" for the data created, and left behind, by apps and applications in the computing model that is currently prevalent: +Most data today is either intrinsically linked to one specific application, that controls and limits access to the actual information, +or even worse, stored in the cloud where users have no direct access at all and depend soley on online tools that require a stable network connection +and a modern browser, and that could be modified, removed or otherwise negatively impacted at any moment. + +This issue is worsened by the fact that the a lot of software we use today is deployed through the cloud computing and SaaS paradigms, +which are far less reliable than earlier means of distributing software: +Software that runs in the cloud is subject to outages due to network problems, +pricing or availability changes etc. at the whim of the company providing it, as well as ISPs involved in the distribution. +Cloud software, as well as subscription-model software with online-verification mechanisms are additionally subject +to license changes, updates modifiying, restricting or simply removing past functionality etc. +Additionally, many cloud software solutions and ecosystems store the users' data in the cloud, +where they are subject to foreign laws and privacy concerns are intransparently handled by the companies. +Should the company, for any reason, be unable or unwanting to continue servicing a customer, +the data may be irrecoverably lost (or access prevented). + +Data rarely really fits the metaphora of files very well, +and even when it does it is rarely exposed to the user that way: +The 'Contacts' app on a mobile phone or laptop for example does not store each contacts's information +in a separate 'file' (as the metaphora may have initially suggested), +but rather keeps this database hidden away from the user. +Consequently, access to the information contained in the database is only enabled through the contacts applications GUI. + +
Note that 'creative' here does not only mean 'artistic': this applies to any field, and it limits the +ability of domain experts to push the boundaries of practice by using technology in innovative ways.
+Creative use of computer technology is limited to programmers, since applications constrain their users to the +paths and abilities that the developers anticipated and deemed useful. + +-- + +Chiusano blames these issues on the metaphor of the *machine*, and likens apps and applications to appliances. +According to him, what should really be provided are *tools*: +composable pieces of software that naturally lend themselves to, or outrightly call for, +integration into the users' other systems and customization, +rather than lure into the walled-gardens of corporate ecosystems using network-effects. + +Data is inert [Cragg 2016] + +Key points: +- data ownership + data needs to be freely accessible (without depending on a 3rd party) and unconditionally accessible +- data compatibility + data needs to be usable outside the context of it's past use (in the worst case) +- functionality + user needs many, complex needs met + + +Today, computer users are losing more and more control over their data. Between web and cloud +applications holding customer data hostage for providing the services, unappealing and limited mobile file +browsing experiences and the non-interoperable, proprietary file formats holding on to their own data has +become infeasible for many users. mmmfs is an attempt at rethinking file-systems and the computer user +experience to give control back to and empower users. + +mmmfs tries to provide a filesystem that is powerful enough to let you use it as your canvas for thinking, +and working at the computer. mmmfs is made for more than just storing information. Files in mmmfs can interact +and morph to create complex behaviours. diff --git a/root/articles/mmmfs/print: text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/print: text$moonscript -> fn -> mmm$dom.moon new file mode 100644 index 0000000..693d362 --- /dev/null +++ b/root/articles/mmmfs/print: text$moonscript -> fn -> mmm$dom.moon @@ -0,0 +1,51 @@ +-- main content +-- doesn't have a name prefix (e.g. preview: fn -> mmm/dom) +-- uses the 'fn ->' conversion to execute the lua function on @get +-- resolves to a value of type mmm/dom +=> + html = require 'mmm.dom' + import article, h1, h2, h3, section, p, div, a, sup, ol, li, span, code, pre, br from html + import moon from (require 'mmm.highlighting').languages + + article with _this = class: 'sidenote-container', style: { 'max-width': '640px' } + append = (a) -> table.insert _this, a + + footnote, getnotes = do + local * + notes = {} + + id = (i) -> "footnote-#{i}" + + footnote = (stuff) -> + i = #notes + 1 + notes[i] = stuff + sup a "[#{i}]", style: { 'text-decoration': 'none' }, href: '#' .. id i + + footnote, -> + args = for i, note in ipairs notes + li (span (tostring i), id: id i), ': ', note + notes = {} + table.insert args, style: { 'list-style': 'none', 'font-size': '0.8em' } + ol table.unpack args + + append h1 'Empowered End-User Computing', style: { 'margin-bottom': 0 } + append p "A Historical Investigation and Development of a File-System-Based Environment", style: { 'margin-top': 0, 'padding-bottom': '0.2em', 'border-bottom': '1px solid black' } + + -- render a preview block + do_section = (child) -> + -- get 'title' as 'text/plain' (error if no value or conversion possible) + title = (child\get 'title: text/plain') or child\gett 'name: alpha' + + -- get 'preview' as a DOM description (nil if no value or conversion possible) + content = (child\get 'preview: mmm/dom') or child\get 'mmm/dom' + + section { + h3 title, style: { margin: 0, cursor: 'pointer' }, onclick: -> BROWSER\navigate child.path + content or span '(no renderable content)', style: { color: 'red' }, + } + + for child in *@children + append (child\get 'print: mmm/dom') or (child\gett 'mmm/dom') + -- do_section child + + append getnotes! diff --git a/root/articles/mmmfs/problem-statement/text$markdown+sidenotes.md b/root/articles/mmmfs/problem-statement/text$markdown+sidenotes.md deleted file mode 100644 index 4723f01..0000000 --- a/root/articles/mmmfs/problem-statement/text$markdown+sidenotes.md +++ /dev/null @@ -1,128 +0,0 @@ -# motivation - -The majority of users interacts with modern computing systems in the form of smartphones, laptops or desktop PCs, -using the mainstream operating systems Apple iOS and Mac OS X, Microsoft Windows or Android. - -All of these operating systems share the concept of *Applications* (or *Apps*) as one of the core pieces of their interaction model. -Functionality and capabilities of the digital devices are bundled in, marketed, sold and distributed as *Applications*. - -In addition, a lot of functionality is nowadays delivered in the form of *Web Apps*, which are used inside a *Browser* (which is an *Application* itself). -*Web Apps* often offer similar functionality to other *Applications*, but are subject to some limitations: -In most cases, they are only accessible or functional in the presence of a stable internet connection, -and they have very limited access to the resources of the physical computer they are running on. -For example, they usually cannot interact directly with the file system, hardware peripherals or other applications, -other than through a standardized set of interactions (e.g. selecting a file via a visual menu, capturing audio and video from a webcam, opening another website). - -On the two Desktop Operating Systems (Mac OS X and Windows), file management and the concepts of *Documents* are still central -elements of interactions with the system. The two prevalent smartphone systems deemphasize this concept by only allowing access to the -data actually stored on the device through an app itself. - -This focus on *Applications* as the primary unit of systems can be seen as the root cause of multiple problems: -Because applications are the products companies produce, and software represents a market of users, -developers compete on features integrated into their applications. - -However this lack of control over data access is not the only problem the application-centric approach induces: -A consequence of this is that interoperability between applications and data formats is rare. -To stay relevant, monlithic software or software suites are designed to -As a result applications tend to accrete features rather then modularise and delegate to other software [P Chiusano]. -Because applications are incentivised to keep customers, they make use of network effects to keep customers locked-in. -This often means re-implementing services and functinality that is already available -and integrating it directly in other applications produced by the same organisation. - -This leads to massively complex file formats, -such as for example the .docx format commonly used for storing mostly -textual data enriched with images and videos on occasion. -The docx format is in fact an archive that can contain many virtual files internally, -such as the images and videos referenced before. -However this is completely unknown to the operating system, -and so users are unable to access the contents in this way. -As a result, editing an image contained in a word document is far from a trivial task: -first the document has to be opened in a word processing application, -then the image has to be exported from it and saved in its own, temporary file. -This file can then be edited and saved back to disk. -Once updated, the image may be reimported into the .docx document. -If the word-processing application supports this, -the old image may be replaced directly, otherwise the user may have to remove the old image, -insert the new one and carefully ensure that the positioning in the document remains intact. - -https://www.theverge.com/2019/10/7/20904030/adobe-venezuela-photoshop-behance-us-sanctions - - -The application-centric computing paradigm common today is harmful to users, -because it leaves behind "intert" data as D. Cragg calls it: - -[Cragg 2016] -D. Cragg coins the term "inert data" for the data created, and left behind, by apps and applications in the computing model that is currently prevalent: -Most data today is either intrinsically linked to one specific application, that controls and limits access to the actual information, -or even worse, stored in the cloud where users have no direct access at all and depend soley on online tools that require a stable network connection -and a modern browser, and that could be modified, removed or otherwise negatively impacted at any moment. - -This issue is worsened by the fact that the a lot of software we use today is deployed through the cloud computing and SaaS paradigms, -which are far less reliable than earlier means of distributing software: -Software that runs in the cloud is subject to outages due to network problems, -pricing or availability changes etc. at the whim of the company providing it, as well as ISPs involved in the distribution. -Cloud software, as well as subscription-model software with online-verification mechanisms are additionally subject -to license changes, updates modifiying, restricting or simply removing past functionality etc. -Additionally, many cloud software solutions and ecosystems store the users' data in the cloud, -where they are subject to foreign laws and privacy concerns are intransparently handled by the companies. -Should the company, for any reason, be unable or unwanting to continue servicing a customer, -the data may be irrecoverably lost (or access prevented). - -Data rarely really fits the metaphora of files very well, -and even when it does it is rarely exposed to the user that way: -The 'Contacts' app on a mobile phone or laptop for example does not store each contacts's information -in a separate 'file' (as the metaphora may have initially suggested), -but rather keeps this database hidden away from the user. -Consequently, access to the information contained in the database is only enabled through the contacts applications GUI. - --- - -According to some researchers in the field of Human-Computer-Interaction, the state of computing is rather dire. - -It seems that a huge majority of daily computer users have silently accepted -that real control over their most important everyday tool will be forever out of reach, -and surrendered it to the relatively small group of 'programmers' curating their experience. - -- Applications are bad -- Services are worse - - -Chiusano blames these issues on the metaphor of the *machine*, and likens apps and applications to appliances. -According to him, what should really be provided are *tools*: -composable pieces of software that naturally lend themselves to, or outrightly call for, -integration into the users' other systems and customization, -rather than lure into the walled-gardens of corporate ecosystems using network-effects. - -Data is inert [Cragg 2016] - -Key points: -- data ownership - data needs to be freely accessible (without depending on a 3rd party) and unconditionally accessible -- data compatibility - data needs to be usable outside the context of it's past use (in the worst case) -- functionality - user needs many, complex needs met - - -Today, computer users are losing more and more control over their data. Between web and cloud -applications holding customer data hostage for providing the services, unappealing and limited mobile file -browsing experiences and the non-interoperable, proprietary file formats holding on to their own data has -become infeasible for many users. mmmfs is an attempt at rethinking file-systems and the computer user -experience to give control back to and empower users. - -mmmfs tries to provide a filesystem that is powerful enough to let you use it as your canvas for thinking, -and working at the computer. mmmfs is made for more than just storing information. Files in mmmfs can interact -and morph to create complex behaviours. - -Let us take as an example the simple task of collecting and arranging a mixed collection of images, videos -and texts in order to brainstorm. To create an assemblage of pictures and text, many might be tempted to open an -Application like Microsoft Word or Adobe Photoshop and create a new document there. Both photoshop files and -word documents are capable of containing texts and images, but when the files are saved, direct access to the -contained data is lost. It is for example a non-trivial and unenjoyable task to edit an image file contained -in a word document in another application and have the changes apply to the document. In the same way, -text contained in a photoshop document cannot be edited in a text editor of your choice. - -Creative use of computer technology is limited to programmers, since applications constrain their users to the -paths and abilities that the developers anticipated and deemed useful. -Note that 'creative' here does not only encompass 'artistic': this applies to any field and means -that innovative use of technology is unlikely to happen as a result of practice by domain experts. diff --git a/root/articles/mmmfs/references/$order b/root/articles/mmmfs/references/$order index 2388177..96b5c98 100644 --- a/root/articles/mmmfs/references/$order +++ b/root/articles/mmmfs/references/$order @@ -1,4 +1,7 @@ xerox-star +memex +hypercard +wikipedia unix subtext inkandswitch diff --git a/root/articles/mmmfs/references/aspect-ratios/text$bibtex b/root/articles/mmmfs/references/aspect-ratios/text$bibtex index 6536419..37cea92 100644 --- a/root/articles/mmmfs/references/aspect-ratios/text$bibtex +++ b/root/articles/mmmfs/references/aspect-ratios/text$bibtex @@ -1,7 +1,7 @@ @web{aspect:ratios, title = {Aspect-ratio independent UIs}, url = {https://s-ol.nu/aspect-ratios}, - author = {Bekic, S.} + author = {Bekic, Sol} year = {2019}, visited = {2019-12-18}, } diff --git a/root/articles/mmmfs/references/hypercard/text$bibtex b/root/articles/mmmfs/references/hypercard/text$bibtex new file mode 100644 index 0000000..b23cfcb --- /dev/null +++ b/root/articles/mmmfs/references/hypercard/text$bibtex @@ -0,0 +1,6 @@ +@online{hypercard, + title = {Computer Chronicles, Episode 501}, + url = {https://archive.org/details/CC501_hypercard}, + visited = {2019-12-18}, + year = {1987}, +} diff --git a/root/articles/mmmfs/references/linux-exec/text$bibtex b/root/articles/mmmfs/references/linux-exec/text$bibtex index 6d52aa8..4f39fef 100644 --- a/root/articles/mmmfs/references/linux-exec/text$bibtex +++ b/root/articles/mmmfs/references/linux-exec/text$bibtex @@ -1,4 +1,4 @@ -@web{23295968, +@web{linux:exec, title = {How does Linux execute a file?}, url = {https://stackoverflow.com/a/23295724/1598293}, publisher = {stackoverflow.com}, diff --git a/root/articles/mmmfs/references/memex/text$bibtex b/root/articles/mmmfs/references/memex/text$bibtex new file mode 100644 index 0000000..377d756 --- /dev/null +++ b/root/articles/mmmfs/references/memex/text$bibtex @@ -0,0 +1,8 @@ +@article{memex, + author = {Bush, Vannevar}, + title = {As we may think}, + journal = {Atlantic Monthly}, + year = {1945}, + volume = {176}, + pages = {101-108}, +} diff --git a/root/articles/mmmfs/references/poc-or-gtfo/text$bibtex b/root/articles/mmmfs/references/poc-or-gtfo/text$bibtex index 26dda65..7cac092 100644 --- a/root/articles/mmmfs/references/poc-or-gtfo/text$bibtex +++ b/root/articles/mmmfs/references/poc-or-gtfo/text$bibtex @@ -2,5 +2,7 @@ author = {Albertini, Ange}, title = {Abusing file formats; or, Corkami, the Novella}, year = {2015}, - journal = {PoC||GTFO 7}, + journal = {PoC||GTFO}, + volume = {7}, + pages = {18-41}, } diff --git a/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon index 7b86510..333900b 100644 --- a/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon @@ -1,6 +1,9 @@ => html = require 'mmm.dom' - import ol, li from html + import div, h1, ol, li from html - ol for ref in *@children - li ref\gett 'mmm/dom' + div { + h1 "references" + ol for ref in *@children + li ref\gett 'mmm/dom' + } diff --git a/root/articles/mmmfs/references/wikipedia/text$bibtex b/root/articles/mmmfs/references/wikipedia/text$bibtex new file mode 100644 index 0000000..c83b72c --- /dev/null +++ b/root/articles/mmmfs/references/wikipedia/text$bibtex @@ -0,0 +1,6 @@ +@web{wikipedia, + title = {Hyperlink - Wikis}, + url = {https://en.wikipedia.org/wiki/Hyperlink#Wikis}, + publisher = {wikipedia.org}, + visited = {2019-12-18}, +} diff --git a/root/articles/mmmfs/references/xerox-star/text$bibtex b/root/articles/mmmfs/references/xerox-star/text$bibtex new file mode 100644 index 0000000..a75cc3e --- /dev/null +++ b/root/articles/mmmfs/references/xerox-star/text$bibtex @@ -0,0 +1,17 @@ +@article{xerox:star, + author = {Johnson, Jeff et. al}, + title = {The Xerox Star: A Retrospective}, + journal = {Computer}, + issue_date = {September 1989}, + volume = {22}, + number = {9}, + month = sep, + year = {1989}, + issn = {0018-9162}, + pages = {11-26, 28-29}, + url = {http://dx.doi.org/10.1109/2.35211}, + doi = {10.1109/2.35211}, + acmid = {66894}, + publisher = {IEEE Computer Society Press}, + address = {Los Alamitos, CA, USA}, +} -- cgit v1.2.3 From eb599a0c4329cab624f49485845c3e7fbd0054e4 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 27 Dec 2019 17:43:46 +0100 Subject: more write- and referencing --- .../mmmfs/abstract/text$markdown+sidenotes.md | 2 +- .../mmmfs/conclusion/text$markdown+sidenotes.md | 2 +- .../mmmfs/motivation/text$markdown+sidenotes.md | 216 +++++++++++---------- root/articles/mmmfs/references/$order | 5 + root/articles/mmmfs/references/acm-dl/text$bibtex | 2 +- root/articles/mmmfs/references/adobe/text$bibtex | 7 + .../mmmfs/references/appliances/text$bibtex | 7 + .../mmmfs/references/inkandswitch/text$bibtex | 2 +- .../mmmfs/references/ios-files/text$bibtex | 6 + .../mmmfs/references/linux-exec/text$bibtex | 2 +- .../mmmfs/references/osx-files/text$bibtex | 6 + .../mmmfs/references/super-powers/text$bibtex | 7 + .../mmmfs/references/wikipedia/text$bibtex | 2 +- 13 files changed, 155 insertions(+), 111 deletions(-) create mode 100644 root/articles/mmmfs/references/adobe/text$bibtex create mode 100644 root/articles/mmmfs/references/appliances/text$bibtex create mode 100644 root/articles/mmmfs/references/ios-files/text$bibtex create mode 100644 root/articles/mmmfs/references/osx-files/text$bibtex create mode 100644 root/articles/mmmfs/references/super-powers/text$bibtex diff --git a/root/articles/mmmfs/abstract/text$markdown+sidenotes.md b/root/articles/mmmfs/abstract/text$markdown+sidenotes.md index 9ac0894..975fecc 100644 --- a/root/articles/mmmfs/abstract/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/abstract/text$markdown+sidenotes.md @@ -1,4 +1,4 @@ abstract ======== -[tbd] +
[section under construction]
diff --git a/root/articles/mmmfs/conclusion/text$markdown+sidenotes.md b/root/articles/mmmfs/conclusion/text$markdown+sidenotes.md index de38bec..45d3bdf 100644 --- a/root/articles/mmmfs/conclusion/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/conclusion/text$markdown+sidenotes.md @@ -1,4 +1,4 @@ conclusion ========== -[tbd] +
[section under construction]
diff --git a/root/articles/mmmfs/motivation/text$markdown+sidenotes.md b/root/articles/mmmfs/motivation/text$markdown+sidenotes.md index e178f4a..b8a5cac 100644 --- a/root/articles/mmmfs/motivation/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/motivation/text$markdown+sidenotes.md @@ -1,120 +1,126 @@ motivation ========== -The majority of users interacts with modern computing systems in the form of smartphones, laptops or desktop PCs, +application-centric design +-------------------------- + +The majority of users interact with modern computing systems in the form of smartphones, laptops or desktop PCs, using the mainstream operating systems Apple iOS and Mac OS X, Microsoft Windows or Android. -All of these operating systems share the concept of *Applications* (or *Apps*) as one of the core pieces of their interaction model. -Functionality and capabilities of the digital devices are bundled in, marketed, sold and distributed as *Applications*. +All of these operating systems share the concept of *Applications* (or *Apps*) as one of the core pieces of their +interaction model. Functionality and capabilities of the digital devices are bundled in, marketed, sold and distributed +as applications. -In addition, a lot of functionality is nowadays delivered in the form of *Web Apps*, which are used inside a *Browser* (which is an *Application* itself). -*Web Apps* often offer similar functionality to other *Applications*, but are subject to some limitations: -In most cases, they are only accessible or functional in the presence of a stable internet connection, -and they have very limited access to the resources of the physical computer they are running on. -For example, they usually cannot interact directly with the file system, hardware peripherals or other applications, -other than through a standardized set of interactions (e.g. selecting a file via a visual menu, capturing audio and video from a webcam, opening another website). +In addition, a lot of functionality is nowadays delivered in the form of *Web Apps* or *Cloud Services*, which share the +limitations of native applications in addition to more specific issues that will be discussed in a separate section +below. -On the two Desktop Operating Systems (Mac OS X and Windows), file management and the concepts of *Documents* are still central -elements of interactions with the system. The two prevalent smartphone systems deemphasize this concept by only allowing access to the -data actually stored on the device through an app itself. +This focus on applications as the primary unit of systems can be seen as the root cause of multiple problems. -This focus on *Applications* as the primary unit of systems can be seen as the root cause of multiple problems: -Because applications are the products companies produce, and software represents a market of users, -developers compete on features integrated into their applications. +For one, since applications are the products companies produce, and software represents a market of users, +developers compete on features integrated into their applications. To stay relevant, monlithic software or software +suites tend to accrete features rather then modularise and delegate to other software. This makes many software packages more complex and unintuitive than they +need to be, and also cripples interoperability between applications and data formats. -However this lack of control over data access is not the only problem the application-centric approach induces: -A consequence of this is that interoperability between applications and data formats is rare. -To stay relevant, monlithic software or software suites are designed to -As a result applications tend to accrete features rather then modularise and delegate to other software [P Chiusano]. Because applications are incentivised to keep customers, they make use of network effects to keep customers locked-in. -This often means re-implementing services and functinality that is already available -and integrating it directly in other applications produced by the same organisation. - -This leads to massively complex file formats, -such as for example the .docx format commonly used for storing mostly -textual data enriched with images and videos on occasion. -The docx format is in fact an archive that can contain many virtual files internally, -such as the images and videos referenced before. -However this is completely unknown to the operating system, -and so users are unable to access the contents in this way. -As a result, editing an image contained in a word document is far from a trivial task: -first the document has to be opened in a word processing application, -then the image has to be exported from it and saved in its own, temporary file. -This file can then be edited and saved back to disk. -Once updated, the image may be reimported into the .docx document. -If the word-processing application supports this, -the old image may be replaced directly, otherwise the user may have to remove the old image, -insert the new one and carefully ensure that the positioning in the document remains intact. - -Let us take as an example the simple task of collecting and arranging a mixed collection of images, videos -and texts in order to brainstorm. To create an assemblage of pictures and text, many might be tempted to open an -Application like Microsoft Word or Adobe Photoshop and create a new document there. Both photoshop files and -word documents are capable of containing texts and images, but when the files are saved, direct access to the -contained data is lost. It is for example a non-trivial and unenjoyable task to edit an image file contained -in a word document in another application and have the changes apply to the document. In the same way, -text contained in a photoshop document cannot be edited in a text editor of your choice. - - -https://www.theverge.com/2019/10/7/20904030/adobe-venezuela-photoshop-behance-us-sanctions - - -The application-centric computing paradigm common today is harmful to users, -because it leaves behind "inert" data, as D. Cragg calls it: - -[Cragg 2016] -D. Cragg coins the term "inert data" for the data created, and left behind, by apps and applications in the computing model that is currently prevalent: -Most data today is either intrinsically linked to one specific application, that controls and limits access to the actual information, -or even worse, stored in the cloud where users have no direct access at all and depend soley on online tools that require a stable network connection -and a modern browser, and that could be modified, removed or otherwise negatively impacted at any moment. - -This issue is worsened by the fact that the a lot of software we use today is deployed through the cloud computing and SaaS paradigms, -which are far less reliable than earlier means of distributing software: -Software that runs in the cloud is subject to outages due to network problems, -pricing or availability changes etc. at the whim of the company providing it, as well as ISPs involved in the distribution. -Cloud software, as well as subscription-model software with online-verification mechanisms are additionally subject -to license changes, updates modifiying, restricting or simply removing past functionality etc. -Additionally, many cloud software solutions and ecosystems store the users' data in the cloud, -where they are subject to foreign laws and privacy concerns are intransparently handled by the companies. -Should the company, for any reason, be unable or unwanting to continue servicing a customer, -the data may be irrecoverably lost (or access prevented). - -Data rarely really fits the metaphora of files very well, -and even when it does it is rarely exposed to the user that way: -The 'Contacts' app on a mobile phone or laptop for example does not store each contacts's information -in a separate 'file' (as the metaphora may have initially suggested), -but rather keeps this database hidden away from the user. -Consequently, access to the information contained in the database is only enabled through the contacts applications GUI. - -
Note that 'creative' here does not only mean 'artistic': this applies to any field, and it limits the -ability of domain experts to push the boundaries of practice by using technology in innovative ways.
-Creative use of computer technology is limited to programmers, since applications constrain their users to the -paths and abilities that the developers anticipated and deemed useful. - --- - +This often means re-implementing services and functionality that is already available to users, +and integrating it directly in other applications or as a new product by the same organisation. +While this strategy helps big software companies retain customers, it harms the users, who have to navigate a complex +landscape of multiple incompatible, overlapping and competing software ecosystems. +Data of the same kind, a rich-text document for example, can be shared easily within the software systems of a certain +manufacturer, and with other users of the same, but sharing with users of a competing system, even if it has almost the +exact same capabilities, can often be problematic. + +Another issue is that due to the technical challenges of building tools in this system, applications are designed and +developed by experts in application development, rather than experts in the domain of the tool. While developers may +solicit feedback, advice and ideas from domain experts, communication is a barrier. Additionally, domain experts are +generally unfamiliar with the technical possibilities, and may therefore not be able to express feedback that would lead +to more significant advances. +
Note that 'creative' here does not only mean 'artistic': this applies to any field, and limits +the ability of domain experts to push the boundaries of practice by using technology in innovative ways.
+As a result, creative use of computer technology is limited to programmers, since applications constrain their users to +the paths and abilities that the developers anticipated and deemed useful. + +The application-centric computing metaphor treats applications as black boxes, and provides no means to understand, +customize or modify the behaviour of apps, intentionally obscuring the inner-workings of applications and +completely cutting users off from this type of ownership over their technology. While the trend seems to be to further +hide the way desktop operating systems work , mobile systems like +Apple's *iOS* already started out as such so-called *walled gardens*. + +cloud computing +--------------- + +*Web Apps* often offer similar functionality to other *Applications*, but are subject to additional limitations: +In most cases, they are only accessible or functional in the presence of a stable internet connection, +and they have very limited access to the resources of the physical computer they are running on. +For example, they usually cannot interact directly with the file system, hardware peripherals or other applications, +other than through a standardized set of interactions (e.g. selecting a file via a visual menu, capturing audio and +video from a webcam, opening another website). + +Cloud software, as well as subscription-model software with online-verification mechanisms, are additionally subject +to license changes, updates modifiying, restricting or simply removing past functionality etc. Additionally, many cloud +software solutions and ecosystems store the users' data in the cloud, often across national borders, where legal and +privacy concerns are intransparently handled by the companies. If a company, for any reason, is unable or unwanting to +continue servicing a customer, the users data may be irrecoverably lost (or access prevented). This can have serious +consequences, especially for professional users, for whom an inability +to access their tools or their cloud-stored data can pose an existential threat. + +inert data (formats) +-------------------- + +Cragg coins the term "inert data" for the data created, and +left behind, by apps and applications in the computing model that is currently prevalent: Most data today is either +intrinsically linked to one specific application, that controls and limits access to the actual information, or even +worse, stored in the cloud where users have no direct access at all and depend soley on online tools that require a +stable network connection and a modern browser, and that could be modified, removed or otherwise negatively impacted +at any moment. + +Aside from being inaccesible to users, the resulting complex proprietary formats are also opaque and useless to other +applications and the operating system, which often is a huge missed opportunity: +The .docx format for example, commonly used for storing mostly textual data enriched with images and on occasion videos, +is in fact a type of archive that can contain many virtual files internally, such as the various media files contained +within. However this is completely unknown to the user and operating system, and so users are unable to access the +contents in this way. As a result, editing an image contained in a word document is far from a trivial task: first the +document has to be opened in a word processing application, then the image has to be exported from it and saved in its +own, temporary file. This file can then be edited and saved back to disk. Once updated, the image may be reimported +into the .docx document. If the word-processing application supports this, the old image may be replaced directly, +otherwise the user may have to remove the old image, insert the new one and carefully ensure that the positioning in +the document remains intact. + +disjointed filesystems +---------------------- + +The filesystems and file models used on modern computing devices generally operate on the assumption that every +individual file stands for itself. Grouping of files in folders is allowed as a convenience for users, but most +applications only ever concern themselves with a single file at a time, independent of the context the file is stored in +in the filesystem. + +Data rarely really fits this metaphora of individual files very well, and even when it does, it is rarely exposed to +the user that way: The 'Contacts' app on a mobile phone for example does not store each contacts's information in a +separate 'file' (as the metaphora may suggest initially), but rather keeps all information in a single database file, +which is hidden away from the user. Consequently, access to the information contained in the database is only enabled +through the contacts application's graphical interface, and not through other applications that generically operate on +files. + +Another example illustrates how a more powerful file (organisation) system could render such formats and applications +obsolete: Given the simple task of collecting and arranging a mixed collection of images, videos and texts in order to +brainstorm, many might be tempted to open an application like *Microsoft Word* or *Adobe Photoshop* and create a new +document there. Both *Photoshop* files and *Word* documents are capable of containing texts and images, but when such +content is copied into them from external sources, such as other files on the same computer, or quotes and links from +the internet, these relationships are irrevocably lost. As illustrated above, additionally, it becomes a lot harder to +edit the content once it is aggregated as well. To choose an application for this task is a trade-off, because in +applications primarily designed for word processing, arranging content visually is harder and image editing and video +embedding options are limited, while tools better suited to these tasks lack nuance when working with text. + +Rather than face this dilemma, a more sensible system could leave the task of positioning and aggregating content of +different types to one software component, while multiple different software components can be responsible for editing +the individual pieces of content, so that the most appropriate one can be chosen for each element. + + diff --git a/root/articles/mmmfs/references/$order b/root/articles/mmmfs/references/$order index 96b5c98..4fd79ec 100644 --- a/root/articles/mmmfs/references/$order +++ b/root/articles/mmmfs/references/$order @@ -1,3 +1,8 @@ +appliances +osx-files +ios-files +super-powers +adobe xerox-star memex hypercard diff --git a/root/articles/mmmfs/references/acm-dl/text$bibtex b/root/articles/mmmfs/references/acm-dl/text$bibtex index 97b053f..ab7b9db 100644 --- a/root/articles/mmmfs/references/acm-dl/text$bibtex +++ b/root/articles/mmmfs/references/acm-dl/text$bibtex @@ -1,4 +1,4 @@ -@web{acm-dl, +@online{acm-dl, title = {ACM Digital Library}, url = {https://dl.acm.org}, } diff --git a/root/articles/mmmfs/references/adobe/text$bibtex b/root/articles/mmmfs/references/adobe/text$bibtex new file mode 100644 index 0000000..3a83038 --- /dev/null +++ b/root/articles/mmmfs/references/adobe/text$bibtex @@ -0,0 +1,7 @@ +@online{adobe, + title = {Adobe is cutting off users in Venezuela due to US sanctions}, + url = {https://www.theverge.com/2019/10/7/20904030/adobe-venezuela-photoshop-behance-us-sanctions}, + publisher = {The Verge}, + year = {2019}, + visited = {2019-12-18}, +} diff --git a/root/articles/mmmfs/references/appliances/text$bibtex b/root/articles/mmmfs/references/appliances/text$bibtex new file mode 100644 index 0000000..56fa8c8 --- /dev/null +++ b/root/articles/mmmfs/references/appliances/text$bibtex @@ -0,0 +1,7 @@ +@online{appliances, + title = {The future of software, the end of apps, and why UX designers should care about type theory}, + url = {http://pchiusano.github.io/2013-05-22/future-of-software.html}, + author = {Chiusano, Paul}, + year = {2013}, + visited = {2019-12-18}, +} diff --git a/root/articles/mmmfs/references/inkandswitch/text$bibtex b/root/articles/mmmfs/references/inkandswitch/text$bibtex index 48fe03c..8b5f298 100644 --- a/root/articles/mmmfs/references/inkandswitch/text$bibtex +++ b/root/articles/mmmfs/references/inkandswitch/text$bibtex @@ -1,4 +1,4 @@ -@web{inkandswitch, +@online{inkandswitch, title = {End-user Programming}, url = {https://inkandswitch.com/end-user-programming.html}, publisher = {Ink & Switch}, diff --git a/root/articles/mmmfs/references/ios-files/text$bibtex b/root/articles/mmmfs/references/ios-files/text$bibtex new file mode 100644 index 0000000..7ec911c --- /dev/null +++ b/root/articles/mmmfs/references/ios-files/text$bibtex @@ -0,0 +1,6 @@ +@online{ios:files, + title = {Use the Files app on your iPhone, iPad, or iPod touch}, + url = {https://support.apple.com/en-us/HT206481}, + publisher = {Apple}, + visited = {2019-12-27}, +} diff --git a/root/articles/mmmfs/references/linux-exec/text$bibtex b/root/articles/mmmfs/references/linux-exec/text$bibtex index 4f39fef..d514613 100644 --- a/root/articles/mmmfs/references/linux-exec/text$bibtex +++ b/root/articles/mmmfs/references/linux-exec/text$bibtex @@ -1,4 +1,4 @@ -@web{linux:exec, +@online{linux:exec, title = {How does Linux execute a file?}, url = {https://stackoverflow.com/a/23295724/1598293}, publisher = {stackoverflow.com}, diff --git a/root/articles/mmmfs/references/osx-files/text$bibtex b/root/articles/mmmfs/references/osx-files/text$bibtex new file mode 100644 index 0000000..f0b28cb --- /dev/null +++ b/root/articles/mmmfs/references/osx-files/text$bibtex @@ -0,0 +1,6 @@ +@online{osx:files, + title = {Where is "Show Package Contents"}, + url = {https://discussions.apple.com/thread/6740790}, + publisher = {Apple Communities}, + visited = {2019-12-27}, +} diff --git a/root/articles/mmmfs/references/super-powers/text$bibtex b/root/articles/mmmfs/references/super-powers/text$bibtex new file mode 100644 index 0000000..5eabda8 --- /dev/null +++ b/root/articles/mmmfs/references/super-powers/text$bibtex @@ -0,0 +1,7 @@ +@online{super:powers, + title = {Super-powers, but not yours}, + url = {http://object.network/manifesto-negative.html}, + author = {Cragg, Duncan}, + year = {2016}, + visited = {2019-12-18}, +} diff --git a/root/articles/mmmfs/references/wikipedia/text$bibtex b/root/articles/mmmfs/references/wikipedia/text$bibtex index c83b72c..0fa3437 100644 --- a/root/articles/mmmfs/references/wikipedia/text$bibtex +++ b/root/articles/mmmfs/references/wikipedia/text$bibtex @@ -1,4 +1,4 @@ -@web{wikipedia, +@online{wikipedia, title = {Hyperlink - Wikis}, url = {https://en.wikipedia.org/wiki/Hyperlink#Wikis}, publisher = {wikipedia.org}, -- cgit v1.2.3 From dc7ee6dc261d5c3351552ed092c9d7ed66f163cc Mon Sep 17 00:00:00 2001 From: s-ol Date: Sat, 28 Dec 2019 18:48:49 +0100 Subject: more write- and referencing --- .../mmmfs/evaluation/text$markdown+sidenotes.md | 7 +- .../mmmfs/framework/text$markdown+sidenotes.md | 91 ++++++++++++++-------- .../mmmfs/motivation/text$markdown+sidenotes.md | 12 ++- .../print: text$moonscript -> fn -> mmm$dom.moon | 2 +- root/articles/mmmfs/references/$order | 1 + .../mmmfs/references/transclusion/text$bibtex | 10 +++ .../mmmfs/text$moonscript -> fn -> mmm$dom.moon | 2 +- scss/_content.scss | 4 + 8 files changed, 90 insertions(+), 39 deletions(-) create mode 100644 root/articles/mmmfs/references/transclusion/text$bibtex diff --git a/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md b/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md index 812b0c5..abde2fb 100644 --- a/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md @@ -93,10 +93,9 @@ This way, *converts* can be added locally if they only make sense within a given Additionally it could be made possible to use this mechanism to locally override *converts* inherited from further up in the tree, for example to specialize types based on their context in the system. -The biggest downside to this approach would be that it presents another pressure factor for, -while also reincforcing, the hierarchical organization of data, -thereby exacerbating the limits of hierarchical structures.
see also -
+
see also +
The biggest downside to this approach would be that it presents another pressure factor for, while also +reincforcing, the hierarchical organization of data, thereby exacerbating the limits of hierarchical structures. ### code outside of the system At the moment, a large part of the mmmfs codebase is still separate from the content, and developed outside of mmmfs diff --git a/root/articles/mmmfs/framework/text$markdown+sidenotes.md b/root/articles/mmmfs/framework/text$markdown+sidenotes.md index 6fa2d3a..ec08ec4 100644 --- a/root/articles/mmmfs/framework/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/framework/text$markdown+sidenotes.md @@ -2,41 +2,81 @@ evaluation framework ==================== In the following section, I will collect approaches and reviews of different end-user software systems from current -literature, as well as derive and present my own requirements and guiding principles for the development of a new system. +literature, as well as derive and present my own requirements and guiding principles for the development of a new +system. + +qualities +--------- + +*Ink and Switch* suggest three qualities for tools striving to support +end-user programming: + +- *Embodiment*, i.e. reifying central concepts of the programming model as more concrete, tangible objects + in the digital space (for example through visual representation), + in order to reduce cognitive load on the user. +- *Living System*, by which they seem to describe the malleability of a system or environment, + and in particular the ability to make changes at different levels of depth in the system with + very short feedback loops and a feeling of direct experience. +- *In-place toolchain*, denoting the availability of tools to customize and author the experience, + as well as a certain accesibility of these tools, granted by a conceptual affinity between the + use of the tools and general 'passive' use of containing system at large. + +These serve as guiding principles for the design and evaluation of computer systems for end-users, but are by nature +very abstract. The following properties are therefore derived as more concrete proposals based on some more specific +constraints: namely the construction of a system for end-users to keep, structure and display personal information and +thoughts in. + +modularity +---------- The *UNIX Philosophy* describes the software design paradigm pioneered in the creation of the Unix operating system at the AT&T Bell Labs research center in the 1960s. The concepts are considered quite influental and are still notably applied in the Linux community. Many attempts at summaries exist, but the following includes the pieces that are especially relevant even today: -> Even though the UNIX system introduces a number of innovative programs and techniques, no single program or idea makes it work well. -> Instead, what makes it effective is the approach to programming, a philosophy of using the computer. Although that philosophy can't be -> written down in a single sentence, at its heart is the idea that the power of a system comes more from the relationships among programs -> than from the programs themselves. Many UNIX programs do quite trivial things in isolation, but, combined with other programs, -> become general and useful tools. +> Even though the UNIX system introduces a number of innovative programs and techniques, no single program or idea makes +> it work well. Instead, what makes it effective is the approach to programming, a philosophy of using the computer. +> Although that philosophy can't be written down in a single sentence, at its heart is the idea that the power of a +> system comes more from the relationships among programs than from the programs themselves. Many UNIX programs do quite +> trivial things in isolation, but, combined with other programs, become general and useful tools. This approach has multiple benefits with regard to end-user programmability: Assembling the system out of simple, modular pieces means that for any given task a user may want to implement, it is very likely that preexisting parts of the system can help the user realize a solution. Wherever such a preexisting part exists, it pays off designing it in such a way that it is easy to integrate for the user later. Assembling the system as a collection of modular, interacting pieces also enables future growth and customization, since pieces may be swapped out with customized or -alternate software at any time. +alternate software at any time. -Based on this, a modern data storage and processing ecosystem should enable transclusion of both content and behaviours -between contexts. -Content should be able to be transcluded and referenced to facilitate the creation of flexible data formats and interactions, -such that e.g. a slideshow slide can include content in a variety other formats (such as images and text) from anywhere else in the system. -Behaviours should be able to be transcluded and reused to facilitate the creation of ad-hoc sytems and applets based on user needs. -For example a user-created todo list should be able to take advantage of a sketching tool the user already has access to. +Settling on a specific modular design model, and reifying other components of a system in terms of it also corresponds +directly to the concept of *Embodiment* described by Ink & Switch. -The system should enable the quick creation of ad-hoc software. +content transclusion +-------------------- -While there are drawbacks to cloud-storage of data (as outlined above), the utility of distributed systems is acknowledged, -and the system should therefore be able to include content and behaviours via the network. -This ability should be integrated deeply into the system, -so that data can be treated independently of its origin and storage conditions, with as little caveats as possible. +The strengths of modular architectures should similarily also extend into the way the system will be used by users. +If users are to store their information and customized behaviour in such an architecture, then powerful tools need to be +present in order to assemble more complex solutions out of such parts. Therefore static content should be able to be +linked to (as envisioned for the *Memex*, see above), but also to be The term transclusion +refers to the concept of including content from a separate document, possibly stored remotely, by reference rather than +by duplication. See also *transcluded*, +to facilitate the creation of flexible data formats and interactions, such that e.g. a slideshow slide can include +content in a variety other formats (such as images and text) from anywhere else in the system. Behaviours also should be +able to be transcluded and reused to facilitate the creation of ad-hoc sytems and applets based on user needs. For +example a user-created todo list should be able to take advantage of a sketching tool the user already has access to. -The system needs to be browsable and understandable by users. +By forming the immediately user-visible layer of the system out of the same abstractions that the deeper levels of the +system are made of, the sense of a *Living System* is also improved: skills that are learned at one (lower) level of the +system carry on into further interaction with the system on deeper levels, as does progress in understanding the +system's mechanisms. + +While there are drawbacks to cloud-storage of data (as outlined above), the utility of distributed systems is +acknowledged, and the system should therefore be able to include content and behaviours via the network. +This ability should be integrated deeply into the system, so that data can be treated independently of its origin and +storage conditions, with as little caveats as possible. In particular, the interactions of remote data access and +content transclusion should be paid attention to and taken into consideration for a system's design. + +end-user programming +-------------------- In order to provide users full access to their information as well as the computational infrastructure, users need to be able to finely customize and reorganize the smallest pieces to suit their own purposes, @@ -49,16 +89,3 @@ in order to keep the scope of this work appropriate, conventional programming languages are used for the time being. Confidence is placed in the fact that eventually more user-friendly languages will be available and, given the goal of modularity, should be implementable in a straightforward fashion. - -*Ink and Switch* suggest three qualities for tools striving to support -end-user programming: - -- "Embodiment", i.e. reifying central concepts of the programming model as more concrete, tangible objects - in the digital space (for example through visual representation), - in order to reduce cognitive load on the user. -- "Living System", by which they seem to describe the malleability of a system or environment, - and in particular the ability to make changes at different levels of depth in the system with - very short feedback loops and a feeling of direct experience. -- "In-place toolchain", denoting the availability of tools to customize and author the experience, - as well as a certain accesibility of these tools, granted by a conceptual affinity between the - use of the tools and general 'passive' use of containing system at large. diff --git a/root/articles/mmmfs/motivation/text$markdown+sidenotes.md b/root/articles/mmmfs/motivation/text$markdown+sidenotes.md index b8a5cac..4bc9cd4 100644 --- a/root/articles/mmmfs/motivation/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/motivation/text$markdown+sidenotes.md @@ -51,7 +51,7 @@ Apple's *iOS* already started out as such so-called *walled gardens*. cloud computing --------------- -*Web Apps* often offer similar functionality to other *Applications*, but are subject to additional limitations: +*Web Apps* often offer similar functionality to other applications, but are subject to additional limitations: In most cases, they are only accessible or functional in the presence of a stable internet connection, and they have very limited access to the resources of the physical computer they are running on. For example, they usually cannot interact directly with the file system, hardware peripherals or other applications, @@ -117,6 +117,16 @@ Rather than face this dilemma, a more sensible system could leave the task of po different types to one software component, while multiple different software components can be responsible for editing the individual pieces of content, so that the most appropriate one can be chosen for each element. +
+ +To summarize, for various reasons, the metaphors and interfaces of computing interfaces today prevent users from deeply +understanding the software they use and the data they own, from customizing and improving their experience and +interactions, and from properly owning, contextualising and connecting their data. + +Interestingly, these deficits do not appear throughout the history of todays computing systems, but are based in rather +recent developments in the field. In fact the most influental systems in the past aspired to the polar opposites, as i +will show in the next section. + diff --git a/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md b/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md index 9978fcf..bf1ed9b 100644 --- a/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md @@ -44,12 +44,7 @@ running on them, the format of a file is almost completely unknown and at best e Because these various mechanisms are applied at different times by the operating system and applications, it is possible for files to be labelled as or considered as being in different formats at the same time by different components of the system. -
-The difference between changing a file extension and converting a file between two formats is commonly unclear to users, -see for example -Why is it possible to convert a file just by renaming it?, https://askubuntu.com/q/166602 from 2019-12-18 - -
+ This leads to confusion about the factual format of data among users, but can also pose a serious security risk: Under some circumstances it is possible that a file contains maliciously-crafted code and is treated as an executable by one software component, while a security mechanism meant to detect such code determines the same file to be a diff --git a/root/articles/mmmfs/motivation/$order b/root/articles/mmmfs/motivation/$order new file mode 100644 index 0000000..c327490 --- /dev/null +++ b/root/articles/mmmfs/motivation/$order @@ -0,0 +1 @@ +creative diff --git a/root/articles/mmmfs/motivation/creative/text$markdown.md b/root/articles/mmmfs/motivation/creative/text$markdown.md new file mode 100644 index 0000000..9dd6162 --- /dev/null +++ b/root/articles/mmmfs/motivation/creative/text$markdown.md @@ -0,0 +1,2 @@ +Note that 'creative' here does not only mean 'artistic': this applies to any field, and limits the ability of domain +experts to push the boundaries of practice by using technology in innovative ways. diff --git a/root/articles/mmmfs/motivation/text$markdown+sidenotes.md b/root/articles/mmmfs/motivation/text$markdown+sidenotes.md index c3eb637..f0c2e6c 100644 --- a/root/articles/mmmfs/motivation/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/motivation/text$markdown+sidenotes.md @@ -11,12 +11,15 @@ All of these operating systems share the concept of *Applications* (or *Apps*) a interaction model. Functionality and capabilities of the digital devices are bundled in, marketed, sold and distributed as applications. + + In addition, a lot of functionality is nowadays delivered in the form of *Web Apps* or *Cloud Services*, which share the limitations of native applications in addition to more specific issues that will be discussed in a separate section below. This focus on applications as the primary unit of systems can be seen as the root cause of multiple problems. + For one, since applications are the products companies produce, and software represents a market of users, developers compete on features integrated into their applications. To stay relevant, monlithic software or software suites tend to accrete features rather then modularise and delegate to other softwareNote that 'creative' here does not only mean 'artistic': this applies to any field, and limits -the ability of domain experts to push the boundaries of practice by using technology in innovative ways. + As a result, creative use of computer technology is limited to programmers, since applications constrain their users to the paths and abilities that the developers anticipated and deemed useful. diff --git a/root/articles/mmmfs/print: text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/print: text$moonscript -> fn -> mmm$dom.moon index 693d362..0dac590 100644 --- a/root/articles/mmmfs/print: text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/print: text$moonscript -> fn -> mmm$dom.moon @@ -7,7 +7,7 @@ import article, h1, h2, h3, section, p, div, a, sup, ol, li, span, code, pre, br from html import moon from (require 'mmm.highlighting').languages - article with _this = class: 'sidenote-container', style: { 'max-width': '640px' } + article with _this = class: 'sidenote-container', style: { 'max-width': '640px', 'line-height': '1.5' } append = (a) -> table.insert _this, a footnote, getnotes = do diff --git a/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon index 333900b..59b5c54 100644 --- a/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon @@ -2,8 +2,10 @@ html = require 'mmm.dom' import div, h1, ol, li from html + refs = for ref in *@children + li ref\gett 'mmm/dom' div { h1 "references" - ol for ref in *@children - li ref\gett 'mmm/dom' + ol with refs + refs.style = 'line-height': 'normal' } diff --git a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon index 8034805..1939042 100644 --- a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon @@ -7,7 +7,7 @@ import article, h1, h2, h3, section, p, div, a, sup, ol, li, span, code, pre, br from html import moon from (require 'mmm.highlighting').languages - article with _this = class: 'sidenote-container', style: { 'max-width': '640px' } + article with _this = class: 'sidenote-container', style: { 'max-width': '640px', 'line-height': '1.5' } append = (a) -> table.insert _this, a footnote, getnotes = do diff --git a/scss/_content.scss b/scss/_content.scss index 5f7d774..e809204 100644 --- a/scss/_content.scss +++ b/scss/_content.scss @@ -17,6 +17,7 @@ > blockquote { @include left-border; + line-height: normal; margin: 1rem var(--margin-wide); padding: 1rem; background: $gray-bright; @@ -47,6 +48,8 @@ height: inherit; max-width: inherit; + line-height: normal; + .description { text-align: center; } @@ -77,6 +80,7 @@ white-space: pre-wrap; overflow-x: auto; + line-height: normal; background: #1d1f21; color: #c5c8c6; } @@ -103,6 +107,7 @@ margin: 1rem var(--margin-wide); padding: 1rem; + line-height: normal; background: $gray-bright; border-color: $gray-neutral; } diff --git a/scss/_sidenotes.scss b/scss/_sidenotes.scss index ea7520f..2cd4965 100644 --- a/scss/_sidenotes.scss +++ b/scss/_sidenotes.scss @@ -22,9 +22,10 @@ $sidenote-width: 14rem; color: $gray-dark; border-top: 1px solid $gray-dark; - font-size: 0.8em; word-break: break-word; + font-size: 0.8em; + line-height: 1.1; text-align: initial; .hook { @@ -47,6 +48,10 @@ $sidenote-width: 14rem; text-align: right; } + > .markdown > p:first-child { + margin-top: 0; + } + a { display: inline; } -- cgit v1.2.3 From c6ca31d55c2b6986509d25d16b947881a63ad595 Mon Sep 17 00:00:00 2001 From: s-ol Date: Sun, 29 Dec 2019 19:30:58 +0100 Subject: print styling fixes --- scss/_content.scss | 3 +++ scss/_print.scss | 11 ----------- scss/_sidenotes.scss | 1 + 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/scss/_content.scss b/scss/_content.scss index e809204..e40145e 100644 --- a/scss/_content.scss +++ b/scss/_content.scss @@ -47,6 +47,7 @@ width: inherit; height: inherit; max-width: inherit; + break-inside: avoid-page; line-height: normal; @@ -78,6 +79,7 @@ margin: 0 var(--margin-wide); padding: 1em; white-space: pre-wrap; + break-inside: avoid-page; overflow-x: auto; line-height: normal; @@ -110,6 +112,7 @@ line-height: normal; background: $gray-bright; border-color: $gray-neutral; + break-inside: avoid-page; } .well-warning { diff --git a/scss/_print.scss b/scss/_print.scss index 36f2a96..1eac26a 100644 --- a/scss/_print.scss +++ b/scss/_print.scss @@ -4,8 +4,6 @@ } .view { - flex: 1 0 auto; - .content { flex: 1 0 auto; } @@ -20,12 +18,3 @@ size: a4; margin: 2.5cm 0 2.5cm; } - -@page :first { - margin-top: 0; -} - -@page :last { - margin-bottom: 0; -} - diff --git a/scss/_sidenotes.scss b/scss/_sidenotes.scss index 2cd4965..607b713 100644 --- a/scss/_sidenotes.scss +++ b/scss/_sidenotes.scss @@ -27,6 +27,7 @@ $sidenote-width: 14rem; font-size: 0.8em; line-height: 1.1; text-align: initial; + break-inside: avoid-page; .hook { position: absolute; -- cgit v1.2.3 From 5db27ae44907974230dbdfba002182e68e59038e Mon Sep 17 00:00:00 2001 From: s-ol Date: Mon, 30 Dec 2019 19:52:37 +0100 Subject: lots of fixes --- mmm/mmmfs/plugins/cites.moon | 4 + mmm/mmmfs/util.moon | 8 +- root/articles/mmmfs/$order | 2 + .../print: text$moonscript -> fn -> mmm$dom.moon | 2 + .../mmmfs/evaluation/text$markdown+sidenotes.md | 72 +++++----- root/articles/mmmfs/examples/$order | 1 - .../mmmfs/examples/empty/title: text$plain | 1 - .../preview: text$moonscript -> fn -> mmm$dom.moon | 7 - .../mmmfs/examples/gallery/title: text$plain | 2 +- .../preview: text$moonscript -> fn -> mmm$dom.moon | 5 - .../mmmfs/examples/image/title: text$plain | 2 +- .../examples/intro: text$markdown+sidenotes.md | 21 +-- .../examples/markdown/preview: text$markdown.md | 6 - .../mmmfs/examples/markdown/text$markdown.md | 20 +++ .../mmmfs/examples/markdown/title: text$plain | 2 +- .../mmmfs/examples/pinwall/title: text$plain | 2 +- .../examples/text$moonscript -> fn -> mmm$dom.moon | 17 ++- .../mmmfs/framework/text$markdown+sidenotes.md | 10 +- .../text$markdown+sidenotes.md | 20 +-- .../mmmfs/mmmfs/text$markdown+sidenotes.md | 160 +++++++++++---------- root/articles/mmmfs/motivation/$order | 1 + .../mmmfs/motivation/app-types/text$markdown.md | 3 + .../mmmfs/motivation/text$markdown+sidenotes.md | 68 +++++---- .../print: text$moonscript -> fn -> mmm$dom.moon | 47 ++---- root/articles/mmmfs/references/$order | 2 + .../articles/mmmfs/references/dijkstra/text$bibtex | 17 +++ .../mmmfs/references/mime-types/text$bibtex | 14 ++ .../statement-of-originality/text$html+frag.html | 13 ++ .../mmmfs/text$moonscript -> fn -> mmm$dom.moon | 48 ++----- root/articles/mmmfs/title/text$html+frag.html | 21 +++ scss/_content.scss | 22 +++ scss/_footer.scss | 1 - scss/_print.scss | 27 +++- scss/_sidenotes.scss | 4 + 34 files changed, 373 insertions(+), 279 deletions(-) delete mode 100644 root/articles/mmmfs/examples/empty/title: text$plain delete mode 100644 root/articles/mmmfs/examples/gallery/preview: text$moonscript -> fn -> mmm$dom.moon delete mode 100644 root/articles/mmmfs/examples/image/preview: text$moonscript -> fn -> mmm$dom.moon delete mode 100644 root/articles/mmmfs/examples/markdown/preview: text$markdown.md create mode 100644 root/articles/mmmfs/examples/markdown/text$markdown.md create mode 100644 root/articles/mmmfs/motivation/app-types/text$markdown.md create mode 100644 root/articles/mmmfs/references/dijkstra/text$bibtex create mode 100644 root/articles/mmmfs/references/mime-types/text$bibtex create mode 100644 root/articles/mmmfs/statement-of-originality/text$html+frag.html create mode 100644 root/articles/mmmfs/title/text$html+frag.html diff --git a/mmm/mmmfs/plugins/cites.moon b/mmm/mmmfs/plugins/cites.moon index 95a9f01..8bd7b12 100644 --- a/mmm/mmmfs/plugins/cites.moon +++ b/mmm/mmmfs/plugins/cites.moon @@ -33,6 +33,10 @@ format_full = () => \insert "#{dot} " \insert i @journal \insert ", volume #{@volume}" if @volume + else if @series + \insert "#{dot} " + \insert i @series + \insert ", No. #{@number}" if @number \insert ", pages #{@pages}" if @pages \insert "#{dot} #{@publisher}" if @publisher when 'web', 'online' diff --git a/mmm/mmmfs/util.moon b/mmm/mmmfs/util.moon index 4175dd1..9b33fd5 100644 --- a/mmm/mmmfs/util.moon +++ b/mmm/mmmfs/util.moon @@ -16,6 +16,10 @@ tourl = (path) -> find_fileder = (fileder, origin) -> if 'string' == type fileder + if fileder == '' + assert origin, "cannot resolve empty path without origin!" + return origin + if '/' ~= fileder\sub 1, 1 assert origin, "cannot resolve relative path '#{fileder}' without origin!" fileder = "#{origin.path}/#{fileder}" @@ -28,7 +32,6 @@ tourl = (path) -> else assert BROWSER and BROWSER.root, "cannot resolve absolute path '#{fileder}' without BROWSER and root set!" assert (BROWSER.root\walk fileder), "couldn't resolve path '#{fileder}'" - else assert fileder, "no fileder passed." @@ -106,10 +109,9 @@ tourl = (path) -> intext = sup a key, href: "##{id}" - print "STYLE IS '#{opts.style}'" span intext, div { class: 'sidenote' - style: opts.style or 'margin-top: -1rem;' + style: opts.style or 'margin-top: -1.25rem;' div :id, class: 'hook' b key, class: 'ref' diff --git a/root/articles/mmmfs/$order b/root/articles/mmmfs/$order index dd9746b..10dcf5c 100644 --- a/root/articles/mmmfs/$order +++ b/root/articles/mmmfs/$order @@ -1,3 +1,4 @@ +title abstract motivation historical-approaches @@ -7,4 +8,5 @@ examples evaluation conclusion references +statement-of-originality ba_log diff --git a/root/articles/mmmfs/ba_log/print: text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/ba_log/print: text$moonscript -> fn -> mmm$dom.moon index 83c0c2c..d23edbb 100644 --- a/root/articles/mmmfs/ba_log/print: text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/ba_log/print: text$moonscript -> fn -> mmm$dom.moon @@ -4,6 +4,8 @@ import ropairs from require 'mmm.ordered' => div { + class: 'print-ownpage' + h1 link_to @, "appendix: project log" table.unpack for post in *@children continue if post\get 'hidden: bool' diff --git a/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md b/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md index f44e18b..1c8fda7 100644 --- a/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md @@ -7,7 +7,7 @@ and evaluate them with regard to the framework derived in the corresponding sect ### publishing and blogging Since mmmfs has grown out of the need for a versatile CMS for a personal publishing website, it is not surprising to -to see that it is still up to that job. Nevertheless it is worth taking a look at its strengths and weaknesses in this +see that it is still up to that job. Nevertheless it is worth taking a look at its strengths and weaknesses in this context: The system has proven itself perfect for publishing small- and medium-size articles and blog posts, especially for its @@ -15,13 +15,14 @@ ability to flexibly transclude content from any source. This includes diagrams ( videos (as in the documentation in the appendix), but also less conventional media such as interactive diagrams or twitter postings. -On the other hand, the development of the technical framework for this very thesis has posed greater challenges. + +On the other hand, the development of the technical framework for this thesis has posed greater challenges. In particular, the implementation of the reference and sidenote systems are brittle and uninspiring. This is mostly due to the approach of splitting up the thesis into a multitude of fileders, and the current lack of mechanisms to re-capture information spread throughout the resulting history effectively. Another issue is that the system is currently based on the presumption that content can and should be interpreted -separate from its parent and context in most cases. This has made the implementation of sidenotes less idiomatic +separately from its parent and context in most cases. This has made the implementation of sidenotes less idiomatic than initially anticipated. ### pinwall @@ -71,20 +72,20 @@ The parts of the code dealing with the content are essentially identical, except more general `mmm/dom` type-interface, allowing for a greater variety of types of content to be used as slides. ## general concerns -While the system has proven pretty successfuly and moldable to the different use-cases that it has been tested in, +While the system has proven pretty successful and moldable to the different use-cases that it has been tested in, there are also limitations in the proposed system that have become obvious in developing and working with the system. Some of these have been anticipated for some time and concrete research directions for solutions are apparent, while others may be intrinsic limitations in the approach taken. ### global set of converts -In the current system, there exists only a single, global set of *converts* that can be potentially applied -to facets anywhere in the system. +In the current system, there is only a single, global set of *converts* that can be potentially applied to facets +anywhere in the system. Therefore it is necessary to encode behaviour directly (as code) in facets wherever exceptional behaviour is required. For example if a fileder conatining multiple images wants to provide custom UI for each image when viewed independently, this code has to either be attached to every image individually (and redundantly), or added as a global convert. To make sure this convert does not interfere with images elsewhere in the system, it would be necessary to introduce -a new type and change the images to use it, which may present more problems yet and works against the principle of -compatibility the system has been constructed for. +a new type and change the images to use it, which may present even more problems, and works against the principle of +compatibility that the system has been constructed for. A potential direction of research in the future is to allow specifying *converts* as part of the fileder tree. Application of *converts* could then be scoped to their fileders' subtrees, such that for any facet only the *converts* @@ -100,7 +101,7 @@ the hierarchical organization of data, thereby exacerbating the limits of hierar ### code outside of the system At the moment, a large part of the mmmfs codebase is still separate from the content, and developed outside of mmmfs itself. This is a result of the development process of mmmfs and was necessary to start the project as the filesystem -itself matured, but has become a limitation of the user experience now: Potential users of mmmfs would generally start +itself matured, but has now become a limitation of the user experience: potential users of mmmfs would generally start by becoming familiar with the operation of mmmfs from within the system, as this is the expected (and designated) experience developed for them. All of the code that lives outside of the mmmfs tree is therefore invisible and opaque to them, actively limiting their understanding, and thereby the customizability, of the system. @@ -110,8 +111,8 @@ This weakness represents a failure to (fully) implement the quality of a "Living In general however, some portion of code may always have to be left outside of the system. This also wouldn't necessarily represent a problem, but in this case it is particularily relevant -for the global set of *converts* (see above), as well as the layout used to render the web view, -both of which are expected to undergo changes as users adapt the system to their own content types and +for the global set of *converts* (see above), as well as the layout used to render the web view. +Both of these are expected to undergo changes as users adapt the system to their own content types and domains of interest, as well as their visual identity, respectively. ### type system @@ -134,35 +135,32 @@ In much the same way that the application-centric paradigm alienates users from and feeling of ownership of their data by overemphasizing the tools in between, the automagical coercion of data types introduces distance between the user and an understanding of the data in the system. -This poses a threat to the transparency of the system, and a potential lack of the quality of "Embodiment" (see above). +This poses a threat to the transparency of the system, and potentially a lack of the "Embodiment" quality (see above). Potential solutions could be to communicate the conversion path clearly and explicitly together with the content, as well as making this display interactive to encourage experimentation with custom conversion queries. -Emphasising the conversion process more strongly in this way might be able to turn this feature from an opaque -hindrance into a transparent tool using careful UX and UI design. +Emphasising the conversion process more strongly in this way might be a way to turn this feature from an opaque +hindrance into a transparent tool. This should represent a challenge mostly in terms of UX and UI design. ### editing -Because many *converts* are not necessarily reversible, -it is very hard to implement generic ways of editing stored data in the same format it is viewed. -For example, the system trivially converts markdown-formatted text sources into viewable HTML markup, -but it is hardly possible to propagate changes to the viewable HTML back to the markdown source. -This particular instance of the problem might be solvable using a Rich-Text editor, but the general problem -worsens when the conversion path becomes more complex: -If the markdown source was fetched via HTTP from a remote URL (e.g. if the facet's type was `URL -> text/markdown`), -it is not possible to edit the content at all, since the only data owned by the system is the URL string itself, -which is not part of the viewable representation at all. -Similarily, when viewing output that is generated by code (e.g. `text/moonscript -> mmm/dom`), -the code itself is not visible to the user when interacting with the viewable representation, -and if the user wishes to change parts of the representation the system is unable to relate these changes to elements -of the code or assist the user in doing so. - -However even where plain text is used and edited, a shortcoming of the current approach to editing is evident: -The content editor is wholly separate from the visible representation, and only facets of the currently viewed -fileder can be edited. This means that content cannot be edited in its context, which is particularily annoying -due to the fragmentation of content that mmmfs encourages. - -As a result, interacting with the system at large is still a very different experience than editing content (and +Because many *converts* are not necessarily reversible, it is very hard to implement generic ways of editing stored data +in the same format it is viewed. For example, the system trivially converts markdown-formatted text sources into +viewable HTML markup, but it is hardly possible to propagate changes to the viewable HTML back to the markdown source. +This particular instance of the problem might be solvable using a Rich-Text editor, but the general problem worsens when +the conversion path becomes more complex: If the markdown source was fetched via HTTP from a remote URL (e.g. if the +facet's type was `URL -> text/markdown`), it is not possible to edit the content at all, since the only data owned by +the system is the URL string itself, which is not part of the viewable representation. Similarily, when viewing output +that is generated by code (e.g. `text/moonscript -> mmm/dom`), the code itself is not visible to the user, and if the +user wishes to change parts of the representation, the system is unable to relate these changes to elements of the code +or assist the user in doing so. + +However, even where plain text is used and edited, a shortcoming of the current approach to editing is evident: +The content editor is wholly separate from the visible representation, and only facets of the currently viewed fileder +can be edited. This means that content cannot be edited in its context, which is exacerbated by the extreme +fragmentation of content that mmmfs encourages. + +As a result, interacting with the system at large is still a very different experience from editing content (and thereby extending the system) in it. This is expected to represent a major hurdle for users getting started with the -system, and is a major shortcoming in enabling end-user programming as set as a goal for -this project. A future iteration should take care to reconsider how editing can be integrated more holistically -with the other core concepts of the design. +system, and is a major shortcoming in enabling end-user programming, as set as a goal for this project. +A future iteration should carefully reconsider how editing could be integrated more holistically with the other core +concepts of the design. diff --git a/root/articles/mmmfs/examples/$order b/root/articles/mmmfs/examples/$order index 348f5fe..4ee3140 100644 --- a/root/articles/mmmfs/examples/$order +++ b/root/articles/mmmfs/examples/$order @@ -1,6 +1,5 @@ language_support image markdown -empty gallery pinwall diff --git a/root/articles/mmmfs/examples/empty/title: text$plain b/root/articles/mmmfs/examples/empty/title: text$plain deleted file mode 100644 index 911f98b..0000000 --- a/root/articles/mmmfs/examples/empty/title: text$plain +++ /dev/null @@ -1 +0,0 @@ -Hey I'm an almost empty Fileder. diff --git a/root/articles/mmmfs/examples/gallery/preview: text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/examples/gallery/preview: text$moonscript -> fn -> mmm$dom.moon deleted file mode 100644 index 5285629..0000000 --- a/root/articles/mmmfs/examples/gallery/preview: text$moonscript -> fn -> mmm$dom.moon +++ /dev/null @@ -1,7 +0,0 @@ -import div, img, br from require 'mmm.dom' - -=> div { - 'the first pic as a little taste:', - br!, - img src: @children[1]\get 'preview', 'URL -> image/png' -} diff --git a/root/articles/mmmfs/examples/gallery/title: text$plain b/root/articles/mmmfs/examples/gallery/title: text$plain index ad74eec..2e9ef34 100644 --- a/root/articles/mmmfs/examples/gallery/title: text$plain +++ b/root/articles/mmmfs/examples/gallery/title: text$plain @@ -1 +1 @@ -A Gallery of 25 random pictures, come on in! +a gallery of images diff --git a/root/articles/mmmfs/examples/image/preview: text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/examples/image/preview: text$moonscript -> fn -> mmm$dom.moon deleted file mode 100644 index 6c431d0..0000000 --- a/root/articles/mmmfs/examples/image/preview: text$moonscript -> fn -> mmm$dom.moon +++ /dev/null @@ -1,5 +0,0 @@ -import img from require 'mmm.dom' - --- look for main content with 'URL to png' type --- and wrap in an mmm/dom image tag -=> img src: @gett 'URL -> image/png' diff --git a/root/articles/mmmfs/examples/image/title: text$plain b/root/articles/mmmfs/examples/image/title: text$plain index 60a556f..dca924f 100644 --- a/root/articles/mmmfs/examples/image/title: text$plain +++ b/root/articles/mmmfs/examples/image/title: text$plain @@ -1 +1 @@ -Hey I'm like a link to a picture or smth +link to a remote image diff --git a/root/articles/mmmfs/examples/intro: text$markdown+sidenotes.md b/root/articles/mmmfs/examples/intro: text$markdown+sidenotes.md index cce348c..709da5c 100644 --- a/root/articles/mmmfs/examples/intro: text$markdown+sidenotes.md +++ b/root/articles/mmmfs/examples/intro: text$markdown+sidenotes.md @@ -16,16 +16,17 @@ and doesn't render as a paragraph but rather just a line of text. This makes it suitable for denoting formatted-text titles and other small strings of text. The problem of embedding other content together with text comfortably is also solved easily, -becase Markdown allows embedding arbitrary HTML in the document. +because Markdown allows embedding arbitrary HTML in the document. This made it possible to define a set of pseudo-HTML elements in the Markdown-convert, `` and ``, which respectively embed and link to other content native to mmm. ### scientific publishing -
+
One of the 'standard' solutions, LaTeX, is arguably at least as complex as the mmm system proposed here, but has a much narrower scope, since it does not support interaction.
+ Scientific publishing is notoriously complex, involving not only the transclusion of diagrams and other media, but generally requiring precise and consistent control over formatting and layout. Some of these complexities are tedious to manage, but present good opportunities for programmatic @@ -43,9 +44,9 @@ type to convert to a full reference format (to `mmm/dom`) and to an inline side- For convenience, a convert from the `URL -> cite/acm` type has been provided to `URL -> text/bibtex`, which generates links to the ACM Digital Library -API for accessing BibTeX citations for documents in the library. -This means that it is enough to store the link to the ACM DL entry in mmmfs, -and the reference will automatically be fetched (and track potential remote corrections). +API for accessing BibTeX citations for documents in the library. This means that it is enough to store the link to the +ACM DL entry in mmmfs, and the reference will automatically be fetched, and therefore stay up to date with potential +remote corrections. ## pinwall In many situations, in particular for creative work, it is often useful to compile resources of @@ -62,14 +63,14 @@ which enumerates the list of children, wraps each in such a rectangular containe and outputs the list of containers as DOM elements. The position and size of each panel are stored in an ad-hoc facet, encoded in the JSON data format: -`pinwall_info: text/json`. This facet can then set on each child and accessed whenever the script is called +`pinwall_info: text/json`. Such a facet is set on each child and read whenever the script is called to render the children, plugging the values within the facet into the visual styling of the document. The script can also set event handlers that react to user input while the document is loaded, and allow the user to reposition and resize the individual pinwall items by clicking and dragging on the upper border or lower right-hand corner respectively. Whenever a change is made the event handler can then update the value in the `pinwall_info` facet, -so that the script places the content at the updated position and size next time it is invoked. +so that the updated position and size are stored for the next time the pinwall is opened. ## slideshow Another common use of digital documents is as aids in a verbal presentation. @@ -84,8 +85,10 @@ It also allows putting the browser into fullscreen mode to maximise screenspace of the website that may distract from the presentation, and register an event handler for keyboard accelerators for moving through the presentation. -Finally the script simply embeds the first of its child-fileders into the viewport rect. -One the current slide is changed, the next embedded child is simply chosen. +Finally the script simply embeds the first of its child-fileders into the viewport rectangle. +Once the current slide is changed, the next embedded child is simply chosen. + diff --git a/root/articles/mmmfs/examples/markdown/preview: text$markdown.md b/root/articles/mmmfs/examples/markdown/preview: text$markdown.md deleted file mode 100644 index 4b38ef2..0000000 --- a/root/articles/mmmfs/examples/markdown/preview: text$markdown.md +++ /dev/null @@ -1,6 +0,0 @@ -See I have like - -- a list of things -- (two things) - -and some bold **text** and `code tags` with me. diff --git a/root/articles/mmmfs/examples/markdown/text$markdown.md b/root/articles/mmmfs/examples/markdown/text$markdown.md new file mode 100644 index 0000000..880eedb --- /dev/null +++ b/root/articles/mmmfs/examples/markdown/text$markdown.md @@ -0,0 +1,20 @@ +This is a markdown document rendered using [marked][marked] on the client, and [discount][discount] on the server. +All Markdown features are supported, for example there is support for lists... + +- a list of things +- (two things) + +...and syntax-highlighted code tags: + +``` +print "Hello World" +``` + +Since Markdown supports inline HTML, mmmfs shorthands can also be used to embed and reference content from elsewhere in +the system. For example, the title of this fileder can be embedded using +``: + + + +[marked]: https://marked.js.org/ +[discount]: https://luarocks.org/modules/craigb/discount diff --git a/root/articles/mmmfs/examples/markdown/title: text$plain b/root/articles/mmmfs/examples/markdown/title: text$plain index 319068d..7915148 100644 --- a/root/articles/mmmfs/examples/markdown/title: text$plain +++ b/root/articles/mmmfs/examples/markdown/title: text$plain @@ -1 +1 @@ - I'm not even five lines of markdown but i render myself! +markdown content diff --git a/root/articles/mmmfs/examples/pinwall/title: text$plain b/root/articles/mmmfs/examples/pinwall/title: text$plain index 9d29c5d..c629992 100644 --- a/root/articles/mmmfs/examples/pinwall/title: text$plain +++ b/root/articles/mmmfs/examples/pinwall/title: text$plain @@ -1 +1 @@ -A pinwall +a pinwall diff --git a/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon index c79ffcf..1401e95 100644 --- a/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon @@ -13,7 +13,7 @@ title = child\gett 'title', 'text/plain' -- get 'preview' as a DOM description (nil if no value or conversion possible) - content = child\get 'preview', 'mmm/dom' + -- content = child\get 'preview', 'mmm/dom' -- div { -- h4 title, style: { margin: 0, cursor: 'pointer' }, onclick: -> BROWSER\navigate child.path @@ -31,10 +31,15 @@ li link_to child - content = ul for child in *@children - preview child + examples = div { + style: + position: 'relative' + 'margin-top': '4rem' - -- table.insert content, 1, (@gett 'intro: mmm/dom') - -- div content + div "The online version is available at ", (a "s-ol.nu/ba", href: 'https://s-ol.nu/ba'), ".", class: 'sidenote' + "The following examples can be viewed and inspected in the interactive version online:" + ul for child in *@children + preview child + } - div (@gett 'intro: mmm/dom'), content + div (@gett 'intro: mmm/dom'), examples diff --git a/root/articles/mmmfs/framework/text$markdown+sidenotes.md b/root/articles/mmmfs/framework/text$markdown+sidenotes.md index 48e6a2c..f62c581 100644 --- a/root/articles/mmmfs/framework/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/framework/text$markdown+sidenotes.md @@ -22,16 +22,16 @@ end-user programming describes the software design paradigm pioneered in the creation of the Unix operating system at the AT&T Bell Labs research center in the 1960s. The -concepts are considered quite influental and are still notably applied in the Linux community. Many attempts at +concepts are considered quite influential and are still notably applied in the Linux community. Many attempts at summaries exist, but the following includes the pieces that are especially relevant even today: > Even though the UNIX system introduces a number of innovative programs and techniques, no single program or idea makes @@ -47,13 +47,13 @@ in such a way that it is easy to integrate for the user later. Assembling the sy interacting pieces also enables future growth and customization, since pieces may be swapped out with customized or alternate software at any time. -Settling on a specific modular design model, and reifying other components of a system in terms of it also corresponds +Settling on a specific modular design model, and reifying other components of a system in terms of it, also corresponds directly to the concept of *Embodiment* described by Ink & Switch. content transclusion -------------------- -The strengths of modular architectures should similarily also extend into the way the system will be used by users. +The strengths of modular architectures should similarily extend also into the way the system will be used by users. If users are to store their information and customized behaviour in such an architecture, then powerful tools need to be present in order to assemble more complex solutions out of such parts. Therefore static content should be able to be linked to (as envisioned for the *Memex*, see above), but also to be , the concept predates much of the technology that later was used to implement many parts of the vision. + One of the most innovative elements of Bush's predictions is the idea of technologically cross-referenced and connected information, which would later be known and created as *hypertext*. While hypertext powers the majority of today's internet, many of the advantages that Bush imagined have not carried over into the personal use of computers. -There are very few tools for creating personal, highly-interconnected knowledgebases, even though this is technically -feasible, and a proven concept (exemplified for example by the massively successful online encyclopedia +There are very few tools for creating personal, highly-interconnected knowledgebases, even though it is technologically +feasible and a proven concept (exemplified for example by the massively successful online encyclopedia *Wikipedia*). While there are little such tools available today, one of the systems that could be said to have come closest to a -practical implementation of such a Memex-inspired system for personal use might be Apple's *HyperCard*. +practical implementation of a Memex-inspired system for personal use might be Apple's *HyperCard*. In a live demonstration, the creators of the software showcase a system of stacks of cards that together implement, amongst others, a calendar (with yearly and @@ -62,8 +64,8 @@ automatically looking up the card corresponding to a person's first name from a different card. Alongside Spreadsheets, *HyperCard* remains one of the most successful implementations of end-user programming, even -today. While it's technical abilities have been long matched and surpassed by other software (such as the ubiquitous -*Hypertext Markup Language*, HTML), these technical successors have failed the legacy of *HyperCard* as an end-user -tool: while it is easier than ever to publish content on the web (through various social media and microblogging -services), the benefits of hypermedia as a customizable medium for personal management have nearly vanished. -End-users do not create hypertext anymore. +today. While its technical abilities have been long matched and surpassed by other software (such as the ubiquitous +*Hypertext Markup Language*, HTML and the associated programming language *JavaScript*), these technical successors have +failed the legacy of *HyperCard* as an end-user tool: While it is easier than ever to publish content on the web +(through various social media and microblogging services), the benefits of hypermedia as a customizable medium for +personal management have nearly vanished. End-users do not create hypertext anymore. diff --git a/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md b/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md index bf1ed9b..c2bbee5 100644 --- a/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md @@ -20,17 +20,18 @@ Like many data storage models it is based fundamentally on the concept of a hier schematic view of an example tree in a mainstream filesystem In common filesystems, as pictured, data can be organized hierarchically into *folders* (or *directories*), -which serve only as containers of *files*, in which data is actually stored. -While *directories* are fully transparent to both system and user (they can be created, browser, listed and viewed by both), -*files* are, from the system perspective, mostly opaque and inert blocks of data. +which serve only as containers of *files*, in which data is actually stored. While *directories* are fully transparent +to both system and user (they can be created, browsed, listed and viewed by both), *files* are, from the system +perspective, mostly opaque and inert blocks of data. Some metadata, such as file size and access permissions, is associated with each file, but notably the type of data is generally not actually stored in the filesystem, but determined loosely based on multiple heuristics depending on the system and context. Some notable mechanism are: -- Suffixes in the name are often used to indicate what kind of data a file should contain. However there is no standardization -- over this, and often a suffix is used for multiple incompatible versions of a file-format. +- Suffixes at the end of the filename are often used to indicate which kind of data a file contains. However there is no + centralized standardization of suffixes, and often one suffix is used for multiple incompatible versions of a + file-formats, or multiple suffixes are used interchangeably for one format. - Many file-formats specify a specific data-pattern either at the very beginning or very end of a given file. On unix systems the `libmagic` database and library of these so-called *magic constants* is commonly used to guess the file-type based on these fragments of data. @@ -41,44 +42,50 @@ Some notable mechanism are: It should be clear already from this short list that to mainstream operating systems, as well as the applications running on them, the format of a file is almost completely unknown and at best educated guesses can be made. -Because these various mechanisms are applied at different times by the operating system and applications, -it is possible for files to be labelled as or considered as being in different formats at the same time by different -components of the system. - + +Because these various mechanisms are applied at different times by the operating system and applications, it is possible +for files to be labelled or considered as being in different formats at the same time by different components of the +system. + This leads to confusion about the factual format of data among users, but can also pose a serious security risk: Under some circumstances it is possible that a file contains maliciously-crafted code and is treated as an executable by one software component, while a security mechanism meant to detect such code determines the same file to be a legitimate image (the file may in fact be valid in both formats). -In mmmfs, the example above might look like this instead: +In mmmfs, the example above might look like this instead: schematic view of an example mmmfs tree -Superficially, this may look quite similar: there is still only two types of nodes (referred to as *fileders* and *facets*), -and again one of them, the *fileders* are used only to hierarchically organize *facets*. -Unlike *files*, *factes* don't only store a freeform *name*, there is also a dedicated *type* field associated with every *facet*, -that is explicitly designed to be understood and used by the system. +Superficially, this may look quite similar: there is still only two types of nodes (referred to as *fileders* and +*facets*), and again one of them, the *fileders* are used only to hierarchically organize *facets*. Unlike *files*, +*factes* don't only store a freeform *name*, there is also a dedicated *type* field associated with every *facet*, that +is explicitly designed to be understood and used by the system. -Despite the similarities, the semantics of this system are very different: -In mainstream filesystems, each *file* stands for itself only; -i.e. in a *directory*, no relationship between *files* is assumed by default, -and files are most of the time read or used outside of the context they exist in in the filesystem. +Despite the similarities, the semantics of this system are very different: In mainstream filesystems, each *file* stands +for itself only; i.e. in a *directory*, no relationship between *files* is assumed by default, and files are most of the +time read or used outside of the context they exist in in the filesystem. In mmmfs, a *facet* should only ever be considered an aspect of its *fileder*, and never as separate from it. -A *fileder* can contain multiple *facets*, but they are meant to be alternate or equivalent representations of the *fileder* itself. -Though for some uses it is required, software in general does not have to be directly aware of the *facets* existing within a *fileder*, -rather it assumes the presence of content in the representation that it requires, and simple requests it. -The *Type Coercion Engine* (see below) will then attempt to satisfy this request based on the *facets* that are in fact present. +A *fileder* can contain multiple *facets*, but they are meant to be alternate or equivalent representations of the +*fileder* itself. Though for some uses it is required, software in general does not have to be directly aware of the +*facets* existing within a *fileder*, rather it assumes the presence of content in the representation that it requires, +and simple requests it. The *Type Coercion Engine* (see below) will then attempt to satisfy this request based on the +*facets* that are in fact present. -Semantically a *fileder*, like a *directory*, also encompasses all the other *fileders* nested within it (recursively). -Since *fileders* are the primary unit of data to be operated upon, *fileder* nesting emerges as a natural way of structuring complex data, -both for access by the system and applications, as well as the user themself. +Semantically a *fileder*, like a *directory*, also encompasses all the other *fileders* nested within itself +(recursively). Since *fileders* are the primary unit of data to be operated upon, *fileder* nesting emerges as a natural +way of structuring complex data, both for access by the system and its components, as well as the user themself. ## the type system & coercion engine -As mentioned above, *facets* store data alongside its *type*, and when applications require data from a *fileder*, -they specify the *type* (or the list of *types*) that they require the type to be in. - -In the current iteration of the type system, types are simple strings of text and loosely based on MIME-types [TOOD: quote RFC?]. +As mentioned above, *facets* store data alongside its *type*, and when a component of the system requires data from a +*fileder*, it has to specify the *expected type* (or a list of these) that it requires the data to be in. The system +then attempts to coerce one of the existing facets into the *expected type*, if possible. This process can involve many +steps such as converting between similar file formats, running executable code stored in a facet, or fetching remote +content. The component that requested the data is isolated from this process and does not have to deal with any of the +details. + +In the current iteration of the type system, types are simple strings of text and loosely based on MIME-types. MIME types consist of a major- and minor category, and optionally a 'suffix'. Here are some common MIME-types that are also used in mmmfs: @@ -87,29 +94,29 @@ Here are some common MIME-types that are also used in mmmfs: - `image/png` - `image/jpeg` -While these types allow some amount of specifity, they fall short of describing their content especially in cases where formats overlap: -Source code is often distributed in `.tar.gz` archive files (directory-trees that are first bundled into an `application/x-tar` archive, -and then compressed into an `application/gzip` archive). -Using either of these two types is either incorrect or insufficient information to properly treat and extract the contained data. +While these types allow some amount of specifity, they fall short of describing their content especially in cases where +formats overlap: Source code for example is often distributed in `.tar.gz` archive files (directory-trees that are first +bundled into an `application/x-tar` archive, and then compressed into an `application/gzip` archive). Using either of +these two types is respectively incorrect or insufficient information to properly treat and extract the contained data. -To mitigate this problem, mmmfs *types* can be nested. This is denoted in mmmfs *type* strings using the `->` symbol, e.g. the mmmfs-types -`application/gzip -> application/tar -> dirtree` and `URL -> image/jpeg` describe a tar-gz-compressed directory tree and the URL linking to a JPEG-picture respectively. +To mitigate this problem, mmmfs *types* can be nested. This is denoted in mmmfs *type* strings using the `->` symbol, +e.g. the mmmfs *types* `application/gzip -> application/tar -> dirtree` and `URL -> image/jpeg` describe a +tar-gz-compressed directory tree and the URL linking to a JPEG-encoded picture respectively. Depending on the outer type this nesting can mean different things: for URLs the nested type is expected to be found after fetching the URL with HTTP, compression formats are expected to contain contents of the nested types, and executable formats are expected to output data of the nested type. -It is a lot more important to be able to accurately describe the type of a *facet* in mmmfs than in mainstream operating systems, -because while in the latter types are mostly used only associate an application that will then prompt the user about further steps, -mmmfs uses the *type* to automatically find one or more programs to execute to convert or transform the data stored in a *facet* -into the *type* required by the application. +It is a lot more important to be able to accurately describe the type of a *facet* in mmmfs than in mainstream operating +systems, because while in the latter types are mostly used only associate an application that will then prompt the user +for further steps if necessary, mmmfs uses the *type* to automatically find one or more programs to execute, in order to +convert or transform the data stored in a *facet* into the *type* required in the context where it was requested. -This process of *type coercion* uses a database of known *converts*, that can be applied to data. -Every *convert* consists of a description of the input *types* that it can accept, the output *type* it would produce for a given input type, -as well as the code for actually converting a given piece of data. -Simple *converts* may simply consist of a fixed in and output type, -such as for example this *convert* for rendering Markdown-encoded text to a HTML hypertext fragment: +This process of *type coercion* uses a database of known *converts* that can be applied to data. Every *convert* +consists of a description of the input *types* that it can accept, the output *type* it would produce for a given input +type, as well as the code for actually converting a given piece of data. Simple *converts* may simply consist of a fixed +in and output type, such as for example this *convert* for rendering Markdown-encoded text to a HTML hypertext fragment: { inp: 'text/markdown' @@ -129,8 +136,8 @@ Other *converts* on the other hand may accept a wide range of input types: This convert uses a Lua Pattern to specify that it can accept an URL to any type of image, and convert it to an HTML fragment. -By using the pattern substitution syntax provided by the Lua `string.gsub` function, -converts can also make the type they return depend on the input type, as is required often when nested types are unpacked: +By using the pattern substitution syntax provided by the Lua `string.gsub` function, converts can also make the type +they return depend on the input type, as is required often when nested types are unpacked: { inp: 'application/gzip -> (.*)' @@ -139,11 +146,11 @@ converts can also make the type they return depend on the input type, as is requ -- implementation stripped for brevity } -This *convert* accepts an `application/gzip` *type* wrapping any other *type*, and captures that nested type in a pattern group. -It then uses the substituion syntax to specify that nested type as the output of the conversion. +This *convert* accepts an `application/gzip` *type* wrapping any other *type*, and captures that nested type in a +pattern group. It then uses the substituion syntax to specify that nested type as the output of the conversion. For an input *type* of `application/gzip -> image/png` this *convert* would therefore generate the type `image/png`. -To further demonstrate the flexibility using this approach, consider this last example: +This last example further demonstrates the flexibility of this approach: { inp: 'text/moonscript -> (.*)' @@ -154,30 +161,31 @@ To further demonstrate the flexibility using this approach, consider this last e This *convert* transpiles MoonScript source-code into Lua source-code, while keeping the nested type (in this case the result expected when executing either script) the same. -In addition to the attributes shown above, every *convert* is also rated with a *cost* value. -The cost value is meant to roughly estimate both the cost (in terms of computing power) of the conversion, -as well as the accuracy or immediacy of the conversion. -For example, resizing an image to a lower size should have a high cost, because the process is computationally expensive, -but also because a smaller image represents the original image to a lesser degree. -Similarily, an URL to a piece of content is a less immediate representation than the content itself, -so the cost of a *convert* that simply generates the URL to a piece of data should be high even if the process is very cheap to compute. - -Cost is defined in this way to make sure that the result of a type-coercion operation reflects the content that was present as accurately as possible. -It is also important to prevent some nonsensical results from occuring, such as displaying a link to content instead of the content itself because -the link requires less steps to create than completely converting the content does. - -Type coercion is implemented using a general pathfinding algorithm, similar to A\*. -First, the set of given *types* is found by selecting all *facets* of the *fileder* that match the *name* given in the query. -The set of given *types* is marked in green in the following example graph. - -From there the algorithm recursively checks whether it can reach other types by applying all matching *converts* to the type -that is cheapest to reach, excluding any types that have already been exhaustively-searched in this way. -All types it finds, that have not yet been inserted into the set of given types are then added to the set, -so that they may be searched as well. - -The algorithm doesn't stop immediately after reaching a type from the result set, -it continues search until it either completely exhausts the result space, -or until all non-exhaustively searched paths are already higher than the maximum allowed path. -This ensures that the optimal path is found, even if a more expensive path is found more quickly initially. - -excerpt of the graph of conversion paths from two starting facets to mmm/dom +In addition to the attributes shown above, every *convert* is also rated with a *cost* value. The cost value is meant to +roughly estimate both the cost (in terms of computing power) of the conversion, as well as the accuracy or immediacy of +the conversion. For example, resizing an image to a lower size should have a high cost, because the process is +computationally expensive, but also because a smaller image represents the original image to a lesser degree. +Similarily, an URL to a piece of content is a less immediate representation than the content itself, so the cost of a +*convert* that simply generates the URL to a piece of data should be high even if the process is very cheap to compute. + +Cost is defined in this way to make sure that the result of a type-coercion operation reflects the content that was +present as accurately as possible. It is also important to prevent some nonsensical results from occuring, such as +displaying a link to content instead of the content itself because the link is cheaper to create than completely +converting the content does. + +Type coercion is implemented using a general pathfinding algorithm, based on *Dijkstra's Algorithm*. First, the set of given *types* is found by selecting all +*facets* of the *fileder* that match the *name* given in the query. The set of given *types* is marked in green in the +following example graph. +From there the algorithm recursively checks whether it can reach other *types* by applying all matching *converts* to +the *type* that is the cheapest to reach currently, excluding any *types* that have already been exhaustively-searched +in this way. All *types* found that have not yet been inserted into the set of given *types* are then added to the +set, so that they may be searched as well. + +The algorithm doesn't stop immediately after reaching a *type* from the result set, it continues search until it either +completely exhausts the result space, or until all non-exhaustively searched paths already have costs higher than the +allowed maximum. This ensures that the optimal path is found, even if a more expensive path is found more quickly +initially. + +excerpt of the graph of conversion paths from two starting facets to mmm/dom + diff --git a/root/articles/mmmfs/motivation/$order b/root/articles/mmmfs/motivation/$order index c327490..accfc0b 100644 --- a/root/articles/mmmfs/motivation/$order +++ b/root/articles/mmmfs/motivation/$order @@ -1 +1,2 @@ +app-types creative diff --git a/root/articles/mmmfs/motivation/app-types/text$markdown.md b/root/articles/mmmfs/motivation/app-types/text$markdown.md new file mode 100644 index 0000000..aac79d7 --- /dev/null +++ b/root/articles/mmmfs/motivation/app-types/text$markdown.md @@ -0,0 +1,3 @@ +While there can be a distinction between *Native Applications* and *Web Applications* or *Cloud Services*, the following +arguments apply to all different technicalal implementations of this same concept. The problems associated +specifically with Web- and Cloud-based application models will be discussed separately below. diff --git a/root/articles/mmmfs/motivation/text$markdown+sidenotes.md b/root/articles/mmmfs/motivation/text$markdown+sidenotes.md index f0c2e6c..ab18726 100644 --- a/root/articles/mmmfs/motivation/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/motivation/text$markdown+sidenotes.md @@ -7,37 +7,29 @@ application-centric design The majority of users interact with modern computing systems in the form of smartphones, laptops or desktop PCs, using the mainstream operating systems Apple iOS and Mac OS X, Microsoft Windows or Android. + All of these operating systems share the concept of *Applications* (or *Apps*) as one of the core pieces of their interaction model. Functionality and capabilities of the digital devices are bundled in, marketed, sold and distributed -as applications. +as applications. This focus on applications as the primary unit of systems can be seen as the root cause of multiple problems. - - -In addition, a lot of functionality is nowadays delivered in the form of *Web Apps* or *Cloud Services*, which share the -limitations of native applications in addition to more specific issues that will be discussed in a separate section -below. - -This focus on applications as the primary unit of systems can be seen as the root cause of multiple problems. - - -For one, since applications are the products companies produce, and software represents a market of users, +For one, since applications are produced by private companies on the software market, developers compete on features integrated into their applications. To stay relevant, monlithic software or software suites tend to accrete features rather then modularise and delegate to other software. This makes many software packages more complex and unintuitive than they need to be, and also cripples interoperability between applications and data formats. -Because applications are incentivised to keep customers, they make use of network effects to keep customers locked-in. -This often means re-implementing services and functionality that is already available to users, +Because (private) software developers are incentivised to keep customers, they make use of network effects to keep +customers locked-in. This often means re-implementing services and functionality that is already available to users, and integrating it directly in other applications or as a new product by the same organisation. -While this strategy helps big software companies retain customers, it harms the users, who have to navigate a complex +While this strategy helps big software companies retain customers, it harms users, who have to navigate a complex landscape of multiple incompatible, overlapping and competing software ecosystems. Data of the same kind, a rich-text document for example, can be shared easily within the software systems of a certain -manufacturer, and with other users of the same, but sharing with users of a competing system, even if it has almost the +manufacturer and with other users of the same, but sharing with users of a competing system, even if it has almost the exact same capabilities, can often be problematic. -Another issue is that due to the technical challenges of building tools in this system, applications are designed and +Another issue is that due to the technical challenges of development in the this paradigm, applications are designed and developed by experts in application development, rather than experts in the domain of the tool. While developers may -solicit feedback, advice and ideas from domain experts, communication is a barrier. Additionally, domain experts are +solicit feedback, advice, and ideas from domain experts, communication is a barrier. Additionally, domain experts are generally unfamiliar with the technical possibilities, and may therefore not be able to express feedback that would lead to more significant advances. @@ -48,7 +40,7 @@ The application-centric computing metaphor treats applications as black boxes, a customize or modify the behaviour of apps, intentionally obscuring the inner-workings of applications and completely cutting users off from this type of ownership over their technology. While the trend seems to be to further hide the way desktop operating systems work, -mobile systems like Apple's *iOS* already started out as such so-called *walled gardens*. +mobile systems like Apple's *iOS* already started out as such *walled gardens*. cloud computing --------------- @@ -68,15 +60,15 @@ continue servicing a customer, the users data may be irrecoverably lost (or acce consequences, especially for professional users, for whom an inability to access their tools or their cloud-stored data can pose an existential threat. -inert data (formats) --------------------- +inert data (and data formats) +----------------------------- Cragg coins the term "inert data" for the data -created, and left behind, by apps and applications in the computing model that is currently prevalent: Most data today +created and left behind by apps and applications in the computing model that is currently prevalent: Most data today is either intrinsically linked to one specific application, that controls and limits access to the actual information, -or even worse, stored in the cloud where users have no direct access at all and depend soley on online tools that -require a stable network connection and a modern browser, and that could be modified, removed or otherwise negatively -impacted at any moment. +or, even worse, stored in the cloud where users have no direct access at all. In the latter case users depend soley on +online tools that require a stable network connection and a modern browser and could be modified, removed, or otherwise +negatively impacted at any moment. Aside from being inaccesible to users, the resulting complex proprietary formats are also opaque and useless to other applications and the operating system, which often is a huge missed opportunity: @@ -98,9 +90,9 @@ individual file stands for itself. Grouping of files in folders is allowed as a applications only ever concern themselves with a single file at a time, independent of the context the file is stored in in the filesystem. -Data rarely really fits this metaphora of individual files very well, and even when it does, it is rarely exposed to +Data rarely really fits this concept of individual files very well, and even when it does, it is rarely exposed to the user that way: The 'Contacts' app on a mobile phone for example does not store each contacts's information in a -separate 'file' (as the metaphora may suggest initially), but rather keeps all information in a single database file, +separate 'file' (as the word may suggest initially), but rather keeps all information in a single database file, which is hidden away from the user. Consequently, access to the information contained in the database is only enabled through the contacts application's graphical interface, and not through other applications that generically operate on files. @@ -111,21 +103,25 @@ brainstorm, many might be tempted to open an application like *Microsoft Word* o document there. Both *Photoshop* files and *Word* documents are capable of containing texts and images, but when such content is copied into them from external sources, such as other files on the same computer, or quotes and links from the internet, these relationships are irrevocably lost. As illustrated above, additionally, it becomes a lot harder to -edit the content once it is aggregated as well. To choose an application for this task is a trade-off, because in -applications primarily designed for word processing, arranging content visually is harder and image editing and video -embedding options are limited, while tools better suited to these tasks lack nuance when working with text. - -Rather than face this dilemma, a more sensible system could leave the task of positioning and aggregating content of -different types to one software component, while multiple different software components can be responsible for editing -the individual pieces of content, so that the most appropriate one can be chosen for each element. +edit the content once it is aggregated. To choose an application for this task is a hard trade-off to make, because in +applications primarily designed for word processing, arranging content visually is hard to do, and image editing and +video embedding options are limited, while tools better suited to these tasks lack nuance when working with text. + +To avoid facing this dilemma, a more sensible system could leave the task of positioning and aggregating content of +different types to one software component, while multiple different software components could be responsible for editing +the individual pieces of content, so that the most appropriate one can be chosen for each element. While creating the +technological interface between these components is certainly a challenge, the resulting system would greatly benefit +from the exponentially-growing capabilties resulting from the modular reuse of components across many contexts: A rich +text editor component could be used for example not just in a mixed media collection as proposed above, but also for +an email editor or the input fields in a browser.
-To summarize, for various reasons, the metaphors and interfaces of computing interfaces today prevent users from deeply -understanding the software they use and the data they own, from customizing and improving their experience and +To summarize, for various reasons, the metaphors and driving concepts of computing interfaces today prevent users from +deeply understanding the software they use and the data they own, from customizing and improving their experience and interactions, and from properly owning, contextualising and connecting their data. -Interestingly, these deficits do not appear throughout the history of todays computing systems, but are based in rather +Interestingly, these deficits do not appear throughout the history of today's computing systems, but are based in rather recent developments in the field. In fact the most influental systems in the past aspired to the polar opposites, as i will show in the next section. diff --git a/root/articles/mmmfs/print: text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/print: text$moonscript -> fn -> mmm$dom.moon index 0dac590..615075a 100644 --- a/root/articles/mmmfs/print: text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/print: text$moonscript -> fn -> mmm$dom.moon @@ -4,48 +4,23 @@ -- resolves to a value of type mmm/dom => html = require 'mmm.dom' - import article, h1, h2, h3, section, p, div, a, sup, ol, li, span, code, pre, br from html + import article, h1, p, div from html import moon from (require 'mmm.highlighting').languages - article with _this = class: 'sidenote-container', style: { 'max-width': '640px', 'line-height': '1.5' } + article with _this = class: 'sidenote-container spacious', style: { 'max-width': '640px', 'line-height': '1.5' } append = (a) -> table.insert _this, a - footnote, getnotes = do - local * - notes = {} + append div { + h1 'Empowered End-User Computing', style: { 'margin-bottom': 0 } + p { + style: + 'margin-top': 0 + 'padding-bottom': '0.2em' + 'border-bottom': '1px solid black' - id = (i) -> "footnote-#{i}" - - footnote = (stuff) -> - i = #notes + 1 - notes[i] = stuff - sup a "[#{i}]", style: { 'text-decoration': 'none' }, href: '#' .. id i - - footnote, -> - args = for i, note in ipairs notes - li (span (tostring i), id: id i), ': ', note - notes = {} - table.insert args, style: { 'list-style': 'none', 'font-size': '0.8em' } - ol table.unpack args - - append h1 'Empowered End-User Computing', style: { 'margin-bottom': 0 } - append p "A Historical Investigation and Development of a File-System-Based Environment", style: { 'margin-top': 0, 'padding-bottom': '0.2em', 'border-bottom': '1px solid black' } - - -- render a preview block - do_section = (child) -> - -- get 'title' as 'text/plain' (error if no value or conversion possible) - title = (child\get 'title: text/plain') or child\gett 'name: alpha' - - -- get 'preview' as a DOM description (nil if no value or conversion possible) - content = (child\get 'preview: mmm/dom') or child\get 'mmm/dom' - - section { - h3 title, style: { margin: 0, cursor: 'pointer' }, onclick: -> BROWSER\navigate child.path - content or span '(no renderable content)', style: { color: 'red' }, + "A Historical Investigation and Development of a File-System-Based Environment" } + } for child in *@children append (child\get 'print: mmm/dom') or (child\gett 'mmm/dom') - -- do_section child - - append getnotes! diff --git a/root/articles/mmmfs/references/$order b/root/articles/mmmfs/references/$order index 01b0c04..1e250b7 100644 --- a/root/articles/mmmfs/references/$order +++ b/root/articles/mmmfs/references/$order @@ -16,3 +16,5 @@ acm-dl aspect-ratios alternatives-to-trees transclusion +mime-types +dijkstra diff --git a/root/articles/mmmfs/references/dijkstra/text$bibtex b/root/articles/mmmfs/references/dijkstra/text$bibtex new file mode 100644 index 0000000..c38a470 --- /dev/null +++ b/root/articles/mmmfs/references/dijkstra/text$bibtex @@ -0,0 +1,17 @@ +@article{10.1007/BF01386390, + author = {Dijkstra, Edsger W.}, + title = {A Note on Two Problems in Connexion with Graphs}, + year = {1959}, + issue_date = {December 1959}, + publisher = {Springer-Verlag}, + address = {Berlin, Heidelberg}, + volume = {1}, + number = {1}, + issn = {0029-599X}, + url = {https://doi.org/10.1007/BF01386390}, + doi = {10.1007/BF01386390}, + journal = {Numer. Math.}, + month = dec, + pages = {269–271}, + numpages = {3} +} diff --git a/root/articles/mmmfs/references/mime-types/text$bibtex b/root/articles/mmmfs/references/mime-types/text$bibtex new file mode 100644 index 0000000..c49b553 --- /dev/null +++ b/root/articles/mmmfs/references/mime-types/text$bibtex @@ -0,0 +1,14 @@ +@article{rfc6838, + series = {Request for Comments}, + number = 6838, + howpublished = {RFC 6838}, + publisher = {Internet Engineering Task Force}, + doi = {10.17487/RFC6838}, + url = {https://tools.ietf.org/html/rfc6838}, + author = {Freed, Ned and Klensin, John C. and Hansen, Tony}, + title = {Media Type Specifications and Registration Procedures}, + pagetotal = 32, + year = 2013, + month = jan, + abstract = {This document defines procedures for the specification and registration of media types for use in HTTP, MIME, and other Internet protocols. This memo documents an Internet Best Current Practice.}, +} diff --git a/root/articles/mmmfs/statement-of-originality/text$html+frag.html b/root/articles/mmmfs/statement-of-originality/text$html+frag.html new file mode 100644 index 0000000..d5fd76f --- /dev/null +++ b/root/articles/mmmfs/statement-of-originality/text$html+frag.html @@ -0,0 +1,13 @@ + diff --git a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon index 1939042..89c9a7d 100644 --- a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon @@ -4,48 +4,24 @@ -- resolves to a value of type mmm/dom => html = require 'mmm.dom' - import article, h1, h2, h3, section, p, div, a, sup, ol, li, span, code, pre, br from html + import article, h1, p, div from html import moon from (require 'mmm.highlighting').languages - article with _this = class: 'sidenote-container', style: { 'max-width': '640px', 'line-height': '1.5' } + article with _this = class: 'sidenote-container spacious', style: { 'max-width': '640px', 'line-height': '1.5' } append = (a) -> table.insert _this, a - footnote, getnotes = do - local * - notes = {} + append div { + class: 'screen-only' + h1 'Empowered End-User Computing', style: { 'margin-bottom': 0 } + p { + style: + 'margin-top': 0 + 'padding-bottom': '0.2em' + 'border-bottom': '1px solid black' - id = (i) -> "footnote-#{i}" - - footnote = (stuff) -> - i = #notes + 1 - notes[i] = stuff - sup a "[#{i}]", style: { 'text-decoration': 'none' }, href: '#' .. id i - - footnote, -> - args = for i, note in ipairs notes - li (span (tostring i), id: id i), ': ', note - notes = {} - table.insert args, style: { 'list-style': 'none', 'font-size': '0.8em' } - ol table.unpack args - - append h1 'Empowered End-User Computing', style: { 'margin-bottom': 0 } - append p "A Historical Investigation and Development of a File-System-Based Environment", style: { 'margin-top': 0, 'padding-bottom': '0.2em', 'border-bottom': '1px solid black' } - - -- render a preview block - do_section = (child) -> - -- get 'title' as 'text/plain' (error if no value or conversion possible) - title = (child\get 'title: text/plain') or child\gett 'name: alpha' - - -- get 'preview' as a DOM description (nil if no value or conversion possible) - content = (child\get 'preview: mmm/dom') or child\get 'mmm/dom' - - section { - h3 title, style: { margin: 0, cursor: 'pointer' }, onclick: -> BROWSER\navigate child.path - content or span '(no renderable content)', style: { color: 'red' }, + "A Historical Investigation and Development of a File-System-Based Environment" } + } for child in *@children append child\gett 'mmm/dom' - -- do_section child - - append getnotes! diff --git a/root/articles/mmmfs/title/text$html+frag.html b/root/articles/mmmfs/title/text$html+frag.html new file mode 100644 index 0000000..1b0bf03 --- /dev/null +++ b/root/articles/mmmfs/title/text$html+frag.html @@ -0,0 +1,21 @@ + diff --git a/scss/_content.scss b/scss/_content.scss index e40145e..1789397 100644 --- a/scss/_content.scss +++ b/scss/_content.scss @@ -4,6 +4,11 @@ height: inherit; } + ul, ol { + break-before: avoid-page; + break-inside: avoid-page; + } + .wide.markdown, .wide .markdown { max-width: max-content; @@ -25,9 +30,15 @@ } } + p { + orphans: 6; + widows: 6; + } + .markdown, .markdown > p, .markdown > p > a { + p, a { max-width: 100%; } @@ -118,4 +129,15 @@ .well-warning { border-color: $gray-fail; } + + .spacious { + h1, h2, h3 { + margin-top: 1.7em; + } + + h1 + h2, + h2 + h3 { + margin-top: 0; + } + } } diff --git a/scss/_footer.scss b/scss/_footer.scss index 4f1c8bd..6cd73c8 100644 --- a/scss/_footer.scss +++ b/scss/_footer.scss @@ -11,7 +11,6 @@ footer { display: none; } - color: $gray-bright; background: $gray-dark; diff --git a/scss/_print.scss b/scss/_print.scss index 1eac26a..c221fa4 100644 --- a/scss/_print.scss +++ b/scss/_print.scss @@ -1,9 +1,29 @@ +.print-only { + display: none; + + @media print { + display: block; + } +} + +.screen-only { + @media print { + display: none; + } +} + @media print { - h1, h2, h3 { + h1, h2, h3, h4, h5 { break-after: avoid-page; + + + * { + break-before: avoid-page; + } } .view { + flex: 1 0 auto; + .content { flex: 1 0 auto; } @@ -14,6 +34,11 @@ } } +.print-ownpage { + break-before: page; + break-after: page; +} + @page { size: a4; margin: 2.5cm 0 2.5cm; diff --git a/scss/_sidenotes.scss b/scss/_sidenotes.scss index 607b713..0b9effe 100644 --- a/scss/_sidenotes.scss +++ b/scss/_sidenotes.scss @@ -1,5 +1,9 @@ $sidenote-width: 14rem; +:root { + --sidenote-width: #{$sidenote-width}; +} + .sidenote-container { margin-right: $sidenote-width + 1rem; -- cgit v1.2.3 From 2c3977673b94f67779cc439b7b1460f08d8d38df Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 31 Dec 2019 15:11:47 +0100 Subject: table-of-contents, reference order --- mmm/mmmfs/util.moon | 2 +- root/articles/mmmfs/$order | 3 +- root/articles/mmmfs/ba_log/intro: text$markdown.md | 4 + .../print: text$moonscript -> fn -> mmm$dom.moon | 3 +- .../ba_log/text$moonscript -> fn -> mmm$dom.moon | 3 +- root/articles/mmmfs/ba_log/title: text$plain | 1 - .../mmmfs/conclusion/text$markdown+sidenotes.md | 3 +- .../mmmfs/evaluation/text$markdown+sidenotes.md | 23 +++--- .../implementation: text$markdown+sidenotes.md | 88 +++++++++++++++++++++ .../examples/intro: text$markdown+sidenotes.md | 92 +--------------------- .../examples/text$moonscript -> fn -> mmm$dom.moon | 14 +--- .../mmmfs/framework/text$markdown+sidenotes.md | 19 +++-- .../text$markdown+sidenotes.md | 3 +- root/articles/mmmfs/mmmfs/$order | 1 - .../mmmfs/mmmfs/confusion/text$markdown.md | 5 -- .../mmmfs/mmmfs/text$markdown+sidenotes.md | 17 ++-- .../mmmfs/motivation/text$markdown+sidenotes.md | 19 +++-- root/articles/mmmfs/references/$order | 28 +++---- root/articles/mmmfs/references/adobe/text$bibtex | 1 + .../mmmfs/references/ios-files/text$bibtex | 6 -- .../articles/mmmfs/references/renaming/text$bibtex | 6 ++ .../text$moonscript -> fn -> mmm$dom.moon | 2 +- .../statement-of-originality/text$html+frag.html | 2 +- .../mmmfs/table-of-contents/text$html+frag.html | 89 +++++++++++++++++++++ .../mmmfs/text$moonscript -> fn -> mmm$dom.moon | 1 - 25 files changed, 257 insertions(+), 178 deletions(-) create mode 100644 root/articles/mmmfs/ba_log/intro: text$markdown.md delete mode 100644 root/articles/mmmfs/ba_log/title: text$plain create mode 100644 root/articles/mmmfs/examples/implementation: text$markdown+sidenotes.md delete mode 100644 root/articles/mmmfs/mmmfs/confusion/text$markdown.md delete mode 100644 root/articles/mmmfs/references/ios-files/text$bibtex create mode 100644 root/articles/mmmfs/references/renaming/text$bibtex create mode 100644 root/articles/mmmfs/table-of-contents/text$html+frag.html diff --git a/mmm/mmmfs/util.moon b/mmm/mmmfs/util.moon index 9b33fd5..8403438 100644 --- a/mmm/mmmfs/util.moon +++ b/mmm/mmmfs/util.moon @@ -104,7 +104,7 @@ tourl = (path) -> link_to fileder, node, nil, opts.attr when 'sidenote' - key = opts.desc or tostring refs\get! + key = tostring refs\get! id = "sideref-#{key}" intext = sup a key, href: "##{id}" diff --git a/root/articles/mmmfs/$order b/root/articles/mmmfs/$order index 10dcf5c..563d544 100644 --- a/root/articles/mmmfs/$order +++ b/root/articles/mmmfs/$order @@ -1,5 +1,6 @@ title abstract +table-of-contents motivation historical-approaches framework @@ -8,5 +9,5 @@ examples evaluation conclusion references -statement-of-originality ba_log +statement-of-originality diff --git a/root/articles/mmmfs/ba_log/intro: text$markdown.md b/root/articles/mmmfs/ba_log/intro: text$markdown.md new file mode 100644 index 0000000..37366cf --- /dev/null +++ b/root/articles/mmmfs/ba_log/intro: text$markdown.md @@ -0,0 +1,4 @@ +The following pages document the development of the `mmmfs` system described above in the form of a project log. +Please note that the log has been written primarily for viewing using a web browser, and as such makes extensive use of +hyperlinking, and also includes some videos that cannot be reproduced in print. It is therefore recommended to view the +live version of the log online at the following address: [s-ol.nu/ba/log](https://s-ol.nu/ba/log). diff --git a/root/articles/mmmfs/ba_log/print: text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/ba_log/print: text$moonscript -> fn -> mmm$dom.moon index d23edbb..97a6283 100644 --- a/root/articles/mmmfs/ba_log/print: text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/ba_log/print: text$moonscript -> fn -> mmm$dom.moon @@ -6,7 +6,8 @@ import ropairs from require 'mmm.ordered' div { class: 'print-ownpage' - h1 link_to @, "appendix: project log" + h1 (link_to @, "appendix: project log"), id: 'ba-log' + @gett 'intro: mmm/dom' table.unpack for post in *@children continue if post\get 'hidden: bool' diff --git a/root/articles/mmmfs/ba_log/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/ba_log/text$moonscript -> fn -> mmm$dom.moon index 37ffc78..bd2859d 100644 --- a/root/articles/mmmfs/ba_log/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/ba_log/text$moonscript -> fn -> mmm$dom.moon @@ -4,7 +4,8 @@ import ropairs from require 'mmm.ordered' => div { - h1 link_to @, "appendix: project log" + h1 (link_to @, "appendix: project log"), id: 'ba-log' + @gett 'intro: mmm/dom' ul do posts = for post in *@children continue if post\get 'hidden: bool' diff --git a/root/articles/mmmfs/ba_log/title: text$plain b/root/articles/mmmfs/ba_log/title: text$plain deleted file mode 100644 index a440bf3..0000000 --- a/root/articles/mmmfs/ba_log/title: text$plain +++ /dev/null @@ -1 +0,0 @@ -project log diff --git a/root/articles/mmmfs/conclusion/text$markdown+sidenotes.md b/root/articles/mmmfs/conclusion/text$markdown+sidenotes.md index 45d3bdf..0780b23 100644 --- a/root/articles/mmmfs/conclusion/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/conclusion/text$markdown+sidenotes.md @@ -1,4 +1,3 @@ -conclusion -========== +# 7. conclusion
[section under construction]
diff --git a/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md b/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md index 1c8fda7..70b8df5 100644 --- a/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/evaluation/text$markdown+sidenotes.md @@ -1,11 +1,10 @@ -evaluation -========== +# 6. evaluation -## examples +## 6.1 examples In this section I will take a look at the implementations of the example for the use cases outlined above, and evaluate them with regard to the framework derived in the corresponding section above. -### publishing and blogging +### 6.1.1 publishing and blogging Since mmmfs has grown out of the need for a versatile CMS for a personal publishing website, it is not surprising to see that it is still up to that job. Nevertheless it is worth taking a look at its strengths and weaknesses in this context: @@ -25,7 +24,7 @@ Another issue is that the system is currently based on the presumption that cont separately from its parent and context in most cases. This has made the implementation of sidenotes less idiomatic than initially anticipated. -### pinwall +### 6.1.2 pinwall The pinwall example shows some strenghts of the mmmfs system pretty convincingly. The type coercion layer completely abstracts away the complexities of transcluding different types of content, and only positioning and sizing the content, as well as enabling interaction, remain to handle in the pinwall fileder. @@ -40,7 +39,7 @@ take care of capturing and handling JS events. The bulk of complexity is therefo UI layer (in this case the browser), which could feasibly be simplified through a custom abstraction layer or the use of output means other than the web. -### slideshow +### 6.1.3 slideshow A simplified image slideshow example consists of only 20 lines of code and demonstrates how the reactive component framework simplifies the generation of ad-hoc UI dramatically: @@ -71,13 +70,13 @@ such as the fullscreen API and sizing content proportionally to the viewport siz The parts of the code dealing with the content are essentially identical, except that content is transcluded via the more general `mmm/dom` type-interface, allowing for a greater variety of types of content to be used as slides. -## general concerns +## 6.2 general concerns While the system has proven pretty successful and moldable to the different use-cases that it has been tested in, there are also limitations in the proposed system that have become obvious in developing and working with the system. Some of these have been anticipated for some time and concrete research directions for solutions are apparent, while others may be intrinsic limitations in the approach taken. -### global set of converts +### 6.2.1 global set of converts In the current system, there is only a single, global set of *converts* that can be potentially applied to facets anywhere in the system. Therefore it is necessary to encode behaviour directly (as code) in facets wherever exceptional behaviour is required. @@ -98,7 +97,7 @@ further up in the tree, for example to specialize types based on their context i The biggest downside to this approach would be that it presents another pressure factor for, while also reincforcing, the hierarchical organization of data, thereby exacerbating the limits of hierarchical structures. -### code outside of the system +### 6.2.2 code outside of the system At the moment, a large part of the mmmfs codebase is still separate from the content, and developed outside of mmmfs itself. This is a result of the development process of mmmfs and was necessary to start the project as the filesystem itself matured, but has now become a limitation of the user experience: potential users of mmmfs would generally start @@ -115,7 +114,7 @@ for the global set of *converts* (see above), as well as the layout used to rend Both of these are expected to undergo changes as users adapt the system to their own content types and domains of interest, as well as their visual identity, respectively. -### type system +### 6.2.3 type system The currently used type system based on strings and pattern matching has been largely satisfactory, but has proven problematic for some anticipated use cases. It should be considered to switch to a more intricate, @@ -127,7 +126,7 @@ but others could use this information to generate lower-resolution 'thumbnails' Using these mechanisms for example images could be requested with a maximum-resolution constraint to save on bandwidth when embedded in other documents. -### type-coercion +### 6.2.4 type-coercion By giving the system more information about the data it is dealing with, and then relying on the system to automatically transform between data-types, it is easy to lose track of which format data is concretely stored in. @@ -142,7 +141,7 @@ as well as making this display interactive to encourage experimentation with cus Emphasising the conversion process more strongly in this way might be a way to turn this feature from an opaque hindrance into a transparent tool. This should represent a challenge mostly in terms of UX and UI design. -### editing +### 6.2.5 in-system editing Because many *converts* are not necessarily reversible, it is very hard to implement generic ways of editing stored data in the same format it is viewed. For example, the system trivially converts markdown-formatted text sources into viewable HTML markup, but it is hardly possible to propagate changes to the viewable HTML back to the markdown source. diff --git a/root/articles/mmmfs/examples/implementation: text$markdown+sidenotes.md b/root/articles/mmmfs/examples/implementation: text$markdown+sidenotes.md new file mode 100644 index 0000000..d32b0db --- /dev/null +++ b/root/articles/mmmfs/examples/implementation: text$markdown+sidenotes.md @@ -0,0 +1,88 @@ +## 5.1 publishing and blogging +### 5.1.1 blogging +Blogging is pretty straightforward, since it generally just involves publishing lightly-formatted text, +interspersed with media such as images and videos or perhaps social media posts. +Markdown is a great tool for this job, and has been integrated in the system to much success: +There are two different types registered with *converts*: `text/markdown` and `text/markdown+span`. +They both render to HTML (and DOM nodes), so they are immediately viewable as part of the system. +The only difference for `text/markdown+span` is that it is limited to a single line, +and doesn't render as a paragraph but rather just a line of text. +This makes it suitable for denoting formatted-text titles and other small strings of text. + +The problem of embedding other content together with text comfortably is also solved easily, +because Markdown allows embedding arbitrary HTML in the document. +This made it possible to define a set of pseudo-HTML elements in the Markdown-convert, +`` and ``, which respectively embed and link to other content native to mmm. + +### 5.1.2 scientific publishing +
+One of the 'standard' solutions, LaTeX, +is arguably at least as complex as the mmm system proposed here, but has a much narrower scope, +since it does not support interaction. +
+ +Scientific publishing is notoriously complex, involving not only the transclusion of diagrams +and other media, but generally requiring precise and consistent control over formatting and layout. +Some of these complexities are tedious to manage, but present good opportunities for programmatic +systems and media to do work for the writer. + +One such topic is the topic of references. +References appear in various formats at multiple positions in a scientific document; +usually they are referenced via a reduced visual form within the text of the document, +and then shown again with full details at the end of the document. + +For the sake of this thesis, referencing has been implemented using a subset of the popular +BibTeX format for describing citations. Converts have been implemented for the `text/bibtex` +type to convert to a full reference format (to `mmm/dom`) and to an inline side-note reference +(`mmm/dom+link`) that can be transcluded using the `` pseudo-tag. + +For convenience, a convert from the `URL -> cite/acm` type has been provided to `URL -> text/bibtex`, +which generates links to the ACM Digital Library +API for accessing BibTeX citations for documents in the library. This means that it is enough to store the link to the +ACM DL entry in mmmfs, and the reference will automatically be fetched, and therefore stay up to date with potential +remote corrections. + +## 5.2 pinwall +In many situations, in particular for creative work, it is often useful to compile resources of +different types for reference or inspiration, and arrange them spacially so that they can be viewed +at a glance or organized into different contexts etc. +Such a pinwall could serve for example to organise references to articles, +to collect visual inspiration for a moodboard etc. + +As a collection, the Pinwall is primarily mapped to a Fileder in the system. +Any content that is placed within can then be rendered by the Pinwall, +which can constrain every piece of content to a rectangular piece on its canvas. +This is possible through a simple script, e.g. of the type `text/moonscript -> fn -> mmm/dom`, +which enumerates the list of children, wraps each in such a rectangular container, +and outputs the list of containers as DOM elements. + +The position and size of each panel are stored in an ad-hoc facet, encoded in the JSON data format: +`pinwall_info: text/json`. Such a facet is set on each child and read whenever the script is called +to render the children, plugging the values within the facet into the visual styling of the document. + +The script can also set event handlers that react to user input while the document is loaded, +and allow the user to reposition and resize the individual pinwall items by clicking and dragging +on the upper border or lower right-hand corner respectively. +Whenever a change is made the event handler can then update the value in the `pinwall_info` facet, +so that the updated position and size are stored for the next time the pinwall is opened. + +## 5.3 slideshow +Another common use of digital documents is as aids in a verbal presentation. +These often take the form of slideshows, for the creation of which a number of established applications exist. +In simple terms, a slideshow is simply a linear series of screen-sized documents, that can be +advanced (and rewound) one by one using keypresses. + +The implementation of this is rather straightforward as well. +The slideshow as a whole becomes a fileder with a script that generates a designated viewport rectangle, +as well as a control interface with keys for advancing the active slide. +It also allows putting the browser into fullscreen mode to maximise screenspace and remove visual elements +of the website that may distract from the presentation, and register an event handler for keyboard accelerators +for moving through the presentation. + +Finally the script simply embeds the first of its child-fileders into the viewport rectangle. +Once the current slide is changed, the next embedded child is simply chosen. + + diff --git a/root/articles/mmmfs/examples/intro: text$markdown+sidenotes.md b/root/articles/mmmfs/examples/intro: text$markdown+sidenotes.md index 709da5c..7b54d95 100644 --- a/root/articles/mmmfs/examples/intro: text$markdown+sidenotes.md +++ b/root/articles/mmmfs/examples/intro: text$markdown+sidenotes.md @@ -1,94 +1,8 @@ -# examples +# 5. example use-cases To illustrate the capabilities of the proposed system, and to compare the results with the framework introduced above, a number of example use cases have been chosen and implemented from the perspective of a user. In the following section I will introduce these use cases and briefly summarize the implementation approach in terms of the capabilities of the proposed system. -## publishing and blogging -### blogging -Blogging is pretty straightforward, since it generally just involves publishing lightly-formatted text, -interspersed with media such as images and videos or perhaps social media posts. -Markdown is a great tool for this job, and has been integrated in the system to much success: -There are two different types registered with *converts*: `text/markdown` and `text/markdown+span`. -They both render to HTML (and DOM nodes), so they are immediately viewable as part of the system. -The only difference for `text/markdown+span` is that it is limited to a single line, -and doesn't render as a paragraph but rather just a line of text. -This makes it suitable for denoting formatted-text titles and other small strings of text. - -The problem of embedding other content together with text comfortably is also solved easily, -because Markdown allows embedding arbitrary HTML in the document. -This made it possible to define a set of pseudo-HTML elements in the Markdown-convert, -`` and ``, which respectively embed and link to other content native to mmm. - -### scientific publishing -
-One of the 'standard' solutions, LaTeX, -is arguably at least as complex as the mmm system proposed here, but has a much narrower scope, -since it does not support interaction. -
- -Scientific publishing is notoriously complex, involving not only the transclusion of diagrams -and other media, but generally requiring precise and consistent control over formatting and layout. -Some of these complexities are tedious to manage, but present good opportunities for programmatic -systems and media to do work for the writer. - -One such topic is the topic of references. -References appear in various formats at multiple positions in a scientific document; -usually they are referenced via a reduced visual form within the text of the document, -and then shown again with full details at the end of the document. - -For the sake of this thesis, referencing has been implemented using a subset of the popular -BibTeX format for describing citations. Converts have been implemented for the `text/bibtex` -type to convert to a full reference format (to `mmm/dom`) and to an inline side-note reference -(`mmm/dom+link`) that can be transcluded using the `` pseudo-tag. - -For convenience, a convert from the `URL -> cite/acm` type has been provided to `URL -> text/bibtex`, -which generates links to the ACM Digital Library -API for accessing BibTeX citations for documents in the library. This means that it is enough to store the link to the -ACM DL entry in mmmfs, and the reference will automatically be fetched, and therefore stay up to date with potential -remote corrections. - -## pinwall -In many situations, in particular for creative work, it is often useful to compile resources of -different types for reference or inspiration, and arrange them spacially so that they can be viewed -at a glance or organized into different contexts etc. -Such a pinwall could serve for example to organise references to articles, -to collect visual inspiration for a moodboard etc. - -As a collection, the Pinwall is primarily mapped to a Fileder in the system. -Any content that is placed within can then be rendered by the Pinwall, -which can constrain every piece of content to a rectangular piece on its canvas. -This is possible through a simple script, e.g. of the type `text/moonscript -> fn -> mmm/dom`, -which enumerates the list of children, wraps each in such a rectangular container, -and outputs the list of containers as DOM elements. - -The position and size of each panel are stored in an ad-hoc facet, encoded in the JSON data format: -`pinwall_info: text/json`. Such a facet is set on each child and read whenever the script is called -to render the children, plugging the values within the facet into the visual styling of the document. - -The script can also set event handlers that react to user input while the document is loaded, -and allow the user to reposition and resize the individual pinwall items by clicking and dragging -on the upper border or lower right-hand corner respectively. -Whenever a change is made the event handler can then update the value in the `pinwall_info` facet, -so that the updated position and size are stored for the next time the pinwall is opened. - -## slideshow -Another common use of digital documents is as aids in a verbal presentation. -These often take the form of slideshows, for the creation of which a number of established applications exist. -In simple terms, a slideshow is simply a linear series of screen-sized documents, that can be -advanced (and rewound) one by one using keypresses. - -The implementation of this is rather straightforward as well. -The slideshow as a whole becomes a fileder with a script that generates a designated viewport rectangle, -as well as a control interface with keys for advancing the active slide. -It also allows putting the browser into fullscreen mode to maximise screenspace and remove visual elements -of the website that may distract from the presentation, and register an event handler for keyboard accelerators -for moving through the presentation. - -Finally the script simply embeds the first of its child-fileders into the viewport rectangle. -Once the current slide is changed, the next embedded child is simply chosen. - - +The online version is available at [s-ol.nu/ba](https://s-ol.nu/ba). +The following examples can be viewed and inspected in the interactive version online: diff --git a/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon index 1401e95..6c47270 100644 --- a/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/examples/text$moonscript -> fn -> mmm$dom.moon @@ -31,15 +31,7 @@ li link_to child - examples = div { - style: - position: 'relative' - 'margin-top': '4rem' + examples = ul for child in *@children + preview child - div "The online version is available at ", (a "s-ol.nu/ba", href: 'https://s-ol.nu/ba'), ".", class: 'sidenote' - "The following examples can be viewed and inspected in the interactive version online:" - ul for child in *@children - preview child - } - - div (@gett 'intro: mmm/dom'), examples + div (@gett 'intro: mmm/dom'), examples, (@gett 'implementation: mmm/dom') diff --git a/root/articles/mmmfs/framework/text$markdown+sidenotes.md b/root/articles/mmmfs/framework/text$markdown+sidenotes.md index f62c581..81acb02 100644 --- a/root/articles/mmmfs/framework/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/framework/text$markdown+sidenotes.md @@ -1,12 +1,11 @@ -evaluation framework -==================== +# 3. evaluation framework In the following section, I will collect approaches and reviews of different end-user software systems from current literature, as well as derive and present my own requirements and guiding principles for the development of a new system. -qualities ---------- +3.1 qualities of successful end-user computing +---------------------------------------------- *Ink and Switch* suggest three qualities for tools striving to support end-user programming: @@ -26,8 +25,8 @@ very abstract. The following properties are therefore derived as more concrete p constraints: namely the construction of a system for end-users to keep, structure and display personal information and thoughts. -modularity ----------- +3.2 modularity +-------------- The *UNIX Philosophy* describes the software design paradigm pioneered in the creation of the Unix operating system at the AT&T Bell Labs research center in the 1960s. The @@ -50,8 +49,8 @@ alternate software at any time. Settling on a specific modular design model, and reifying other components of a system in terms of it, also corresponds directly to the concept of *Embodiment* described by Ink & Switch. -content transclusion --------------------- +3.3 content transclusion +------------------------ The strengths of modular architectures should similarily extend also into the way the system will be used by users. If users are to store their information and customized behaviour in such an architecture, then powerful tools need to be @@ -76,8 +75,8 @@ This ability should be integrated deeply into the system, so that data can be tr storage conditions, with as little caveats as possible. In particular, the interactions of remote data access and content transclusion should be paid attention to and taken into consideration for a system's design. -end-user programming --------------------- +3.4 end-user programming +------------------------ In order to provide users full access to their information as well as the computational infrastructure, users need to be able to finely customize and reorganize the smallest pieces to suit their own purposes, diff --git a/root/articles/mmmfs/historical-approaches/text$markdown+sidenotes.md b/root/articles/mmmfs/historical-approaches/text$markdown+sidenotes.md index 8829f69..812d751 100644 --- a/root/articles/mmmfs/historical-approaches/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/historical-approaches/text$markdown+sidenotes.md @@ -1,5 +1,4 @@ -historical approaches -===================== +# 2. historical approaches Two of the earliest holistic computing systems, the Xerox Alto and Xerox Star, both developed at Xerox PARC and introduced in the 70s and early 80s, pioneered not only graphical user-interfaces, but also the "Desktop Metaphor". diff --git a/root/articles/mmmfs/mmmfs/$order b/root/articles/mmmfs/mmmfs/$order index ec11aa6..5a5d5ab 100644 --- a/root/articles/mmmfs/mmmfs/$order +++ b/root/articles/mmmfs/mmmfs/$order @@ -1,4 +1,3 @@ -confusion type_coercion_graph tree_mmmfs tree_mainstream diff --git a/root/articles/mmmfs/mmmfs/confusion/text$markdown.md b/root/articles/mmmfs/mmmfs/confusion/text$markdown.md deleted file mode 100644 index 55fe833..0000000 --- a/root/articles/mmmfs/mmmfs/confusion/text$markdown.md +++ /dev/null @@ -1,5 +0,0 @@ -For example, the difference between changing a file extension and converting a file between two formats is often unclear -to users, as evident from questions like this: -Why is it possible to convert a file just by renaming it?, https://askubuntu.com/q/166602 from 2019-12-18 - diff --git a/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md b/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md index c2bbee5..28030d7 100644 --- a/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/mmmfs/text$markdown+sidenotes.md @@ -1,5 +1,4 @@ -mmmfs -===== +# 4. mmmfs `mmmfs` is a newly developed personal data storage and processing system. It was developed first as a tool for generating static websites, but has been extended with live interaction and introspection, as well as embedded @@ -13,7 +12,7 @@ seemlessly extended and molded to the users needs. The abstraction of data types is accomplished using two major components, the *Type System and Coercion Engine* and the *Fileder Unified Data Model* for unified data storage and access. -## the fileder unified data model +## 4.1 the fileder unified data model The Fileder Model is the underlying unified data storage model. Like many data storage models it is based fundamentally on the concept of a hierarchical tree-structure. @@ -42,16 +41,18 @@ Some notable mechanism are: It should be clear already from this short list that to mainstream operating systems, as well as the applications running on them, the format of a file is almost completely unknown and at best educated guesses can be made. - Because these various mechanisms are applied at different times by the operating system and applications, it is possible for files to be labelled or considered as being in different formats at the same time by different components of the system. -This leads to confusion about the factual format of data among users, but can also pose a serious security risk: +This leads to confusion about the factual format of data among usersFor example, the difference between changing a file extension and converting +a file between two formats is often unclear to users, as evident from questions like this: , but can +also pose a serious security risk: Under some circumstances it is possible that a file contains maliciously-crafted code and is treated as an executable by one software component, while a security mechanism meant to detect such code determines the same file to be a -legitimate image (the file may in fact be valid -in both formats). +legitimate image +(the file may in fact be valid in both formats). In mmmfs, the example above might look like this instead: schematic view of an example mmmfs tree @@ -76,7 +77,7 @@ Semantically a *fileder*, like a *directory*, also encompasses all the other *fi (recursively). Since *fileders* are the primary unit of data to be operated upon, *fileder* nesting emerges as a natural way of structuring complex data, both for access by the system and its components, as well as the user themself. -## the type system & coercion engine +## 4.2 the type system & coercion engine As mentioned above, *facets* store data alongside its *type*, and when a component of the system requires data from a *fileder*, it has to specify the *expected type* (or a list of these) that it requires the data to be in. The system then attempts to coerce one of the existing facets into the *expected type*, if possible. This process can involve many diff --git a/root/articles/mmmfs/motivation/text$markdown+sidenotes.md b/root/articles/mmmfs/motivation/text$markdown+sidenotes.md index ab18726..9bfdea5 100644 --- a/root/articles/mmmfs/motivation/text$markdown+sidenotes.md +++ b/root/articles/mmmfs/motivation/text$markdown+sidenotes.md @@ -1,8 +1,7 @@ -motivation -========== +# 1. motivation -application-centric design --------------------------- +1.1 application-centric design +------------------------------ The majority of users interact with modern computing systems in the form of smartphones, laptops or desktop PCs, using the mainstream operating systems Apple iOS and Mac OS X, Microsoft Windows or Android. @@ -42,8 +41,8 @@ completely cutting users off from this type of ownership over their technology. hide the way desktop operating systems work, mobile systems like Apple's *iOS* already started out as such *walled gardens*. -cloud computing ---------------- +1.2 cloud computing +------------------- *Web Apps* often offer similar functionality to other applications, but are subject to additional limitations: In most cases, they are only accessible or functional in the presence of a stable internet connection, @@ -60,8 +59,8 @@ continue servicing a customer, the users data may be irrecoverably lost (or acce consequences, especially for professional users, for whom an inability to access their tools or their cloud-stored data can pose an existential threat. -inert data (and data formats) ------------------------------ +1.3 inert data (and data formats) +--------------------------------- Cragg coins the term "inert data" for the data created and left behind by apps and applications in the computing model that is currently prevalent: Most data today @@ -82,8 +81,8 @@ into the .docx document. If the word-processing application supports this, the o otherwise the user may have to remove the old image, insert the new one and carefully ensure that the positioning in the document remains intact. -disjointed filesystems ----------------------- +1.4 disjointed filesystems +-------------------------- The filesystems and file models used on modern computing devices generally operate on the assumption that every individual file stands for itself. Grouping of files in folders is allowed as a convenience for users, but most diff --git a/root/articles/mmmfs/references/$order b/root/articles/mmmfs/references/$order index 1e250b7..f50f166 100644 --- a/root/articles/mmmfs/references/$order +++ b/root/articles/mmmfs/references/$order @@ -1,20 +1,20 @@ +poc-or-gtfo +aspect-ratios +memex appliances -osx-files -ios-files super-powers -adobe +dijkstra +subtext +mime-types +alternatives-to-trees xerox-star -memex -hypercard -wikipedia unix -subtext +transclusion +adobe +acm-dl +hypercard inkandswitch linux-exec -poc-or-gtfo -acm-dl -aspect-ratios -alternatives-to-trees -transclusion -mime-types -dijkstra +wikipedia +osx-files +renaming diff --git a/root/articles/mmmfs/references/adobe/text$bibtex b/root/articles/mmmfs/references/adobe/text$bibtex index 3a83038..fccef37 100644 --- a/root/articles/mmmfs/references/adobe/text$bibtex +++ b/root/articles/mmmfs/references/adobe/text$bibtex @@ -2,6 +2,7 @@ title = {Adobe is cutting off users in Venezuela due to US sanctions}, url = {https://www.theverge.com/2019/10/7/20904030/adobe-venezuela-photoshop-behance-us-sanctions}, publisher = {The Verge}, + author = {Lee, Dami}, year = {2019}, visited = {2019-12-18}, } diff --git a/root/articles/mmmfs/references/ios-files/text$bibtex b/root/articles/mmmfs/references/ios-files/text$bibtex deleted file mode 100644 index 7ec911c..0000000 --- a/root/articles/mmmfs/references/ios-files/text$bibtex +++ /dev/null @@ -1,6 +0,0 @@ -@online{ios:files, - title = {Use the Files app on your iPhone, iPad, or iPod touch}, - url = {https://support.apple.com/en-us/HT206481}, - publisher = {Apple}, - visited = {2019-12-27}, -} diff --git a/root/articles/mmmfs/references/renaming/text$bibtex b/root/articles/mmmfs/references/renaming/text$bibtex new file mode 100644 index 0000000..a4aa714 --- /dev/null +++ b/root/articles/mmmfs/references/renaming/text$bibtex @@ -0,0 +1,6 @@ +@online{renaming, + title = {Why is it possible to convert a file just by renaming it?}, + url = {https://askubuntu.com/q/166602}, + publisher = {askubuntu.com}, + visited = {2019-12-18}, +} diff --git a/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon index 59b5c54..7d0622c 100644 --- a/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon @@ -5,7 +5,7 @@ refs = for ref in *@children li ref\gett 'mmm/dom' div { - h1 "references" + h1 "references", id: 'references' ol with refs refs.style = 'line-height': 'normal' } diff --git a/root/articles/mmmfs/statement-of-originality/text$html+frag.html b/root/articles/mmmfs/statement-of-originality/text$html+frag.html index d5fd76f..d6dcbc0 100644 --- a/root/articles/mmmfs/statement-of-originality/text$html+frag.html +++ b/root/articles/mmmfs/statement-of-originality/text$html+frag.html @@ -1,5 +1,5 @@