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 --- root/Tupdefault.lua | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 root/Tupdefault.lua (limited to 'root') 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' -) -- 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 --- root/text$moonscript -> fn -> mmm$dom.moon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'root') 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 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 (limited to 'root') 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 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 (limited to 'root') 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 `",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 7b61518128ac3c666406f76756994a70adede4f2 Mon Sep 17 00:00:00 2001 From: s-ol Date: Thu, 10 Oct 2019 20:58:16 +0200 Subject: fix mmm-embed --- .../_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 -- 6 files changed, 24 insertions(+), 12 deletions(-) (limited to 'root') 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 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 --- .../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 +++ 5 files changed, 3654 insertions(+), 546 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 (limited to 'root') diff --git a/root/articles/realities/text$moonscript -> mmm$component.moon b/root/articles/realities/text$moonscript -> mmm$component.moon new file mode 100644 index 0000000..7689dbb --- /dev/null +++ b/root/articles/realities/text$moonscript -> mmm$component.moon @@ -0,0 +1,542 @@ +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/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 --- root/static/mmm/application$lua.lua | 2701 ----------------------------------- root/static/style/text$css.css | 411 ------ 2 files changed, 3112 deletions(-) delete mode 100644 root/static/mmm/application$lua.lua delete mode 100644 root/static/style/text$css.css (limited to 'root') 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 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(-) (limited to 'root') 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 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 (limited to 'root') 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 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 (limited to 'root') 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 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 --- root/articles/mmmfs/ba_log/2019-10-10/text$markdown.md | 7 +++---- root/articles/realities/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 ++++++++ root/static/highlight-pack/application$javascript.js | 2 -- root/static/highlight-pack/text$javascript.js | 2 ++ 8 files changed, 15 insertions(+), 16 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 (limited to 'root') 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 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 (limited to 'root') 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 (limited to 'root') 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 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 (limited to 'root') 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 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 (limited to 'root') 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 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 (limited to 'root') 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 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 (limited to 'root') 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 (limited to 'root') 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 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 (limited to 'root') 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 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 (limited to 'root') 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 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 (limited to 'root') 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 (limited to 'root') 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 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 --- .../mmmfs/ba_log/2019-10-27/text$markdown.md | 54 +++++++++++----------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'root') 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 d9eafa21ad1d6ad340b5744d69e9fc68ce2083cb Mon Sep 17 00:00:00 2001 From: s-ol Date: Tue, 29 Oct 2019 14:18:16 +0100 Subject: add sandbox --- 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 ++++++++++++++++ 11 files changed, 79 insertions(+) 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 (limited to 'root') 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 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 --- 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 ---------------- 11 files changed, 79 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 (limited to 'root') 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 (limited to 'root') 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 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 (limited to 'root') 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 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 (limited to 'root') 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 5ec1fe2fc943ad4123fac138de70d4152e8b341d Mon Sep 17 00:00:00 2001 From: s-ol Date: Mon, 25 Nov 2019 15:54:28 +0100 Subject: add pinwall example --- 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 + 10 files changed, 133 insertions(+) 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 (limited to 'root') 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 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 (limited to 'root') 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 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(-) (limited to 'root') 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 --- root/articles/mmmfs/ba_log/2019-10-09/text$markdown.md | 2 +- root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'root') 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 -- 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 --- root/articles/mmmfs/$order | 2 +- root/articles/mmmfs/references/$order | 2 ++ root/articles/mmmfs/references/text$markdown.md | 0 .../articles/mmmfs/references/text$moonscript -> fn -> mmm$dom.moon | 6 ++++++ root/articles/mmmfs/references/unix/URL -> cite$acm | 1 + root/articles/mmmfs/references/xerox-star/URL -> cite$acm | 1 + 6 files changed, 11 insertions(+), 1 deletion(-) 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 (limited to 'root') 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 -- 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 --- root/articles/mmmfs/mmmfs/text$markdown.md | 6 ++++-- root/articles/mmmfs/references/$order | 1 + root/articles/mmmfs/references/linux-exec/text$bibtex | 7 +++++++ 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 root/articles/mmmfs/references/linux-exec/text$bibtex (limited to 'root') 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}, +} -- 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 (limited to 'root') 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 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 (limited to 'root') 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 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 (limited to 'root') 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 --- 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 +++ 24 files changed, 381 insertions(+), 223 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 (limited to 'root') 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 (limited to 'root') 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 +- 7 files changed, 86 insertions(+), 39 deletions(-) create mode 100644 root/articles/mmmfs/references/transclusion/text$bibtex (limited to 'root') 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 -- 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 --- 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 +++ 28 files changed, 312 insertions(+), 274 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 (limited to 'root') 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 @@ + -- 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 --- 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 - 24 files changed, 256 insertions(+), 177 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 (limited to 'root') 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 @@