git.s-ol.nu mmm / 9632233
make fileders load just-in-time s-ol 3 years ago
11 changed file(s) with 3801 addition(s) and 623 deletion(s). Raw diff Collapse all Expand all
22 $bundle.lua
33 *.js
44 *.js.map
5 *.lua
88
99 require 'mmm'
1010 require 'lfs'
11 import Fileder, Key from require 'mmm.mmmfs.fileder'
11 import Key from require 'mmm.mmmfs.fileder'
1212 import SQLStore from require 'mmm.mmmfs.stores.sql'
1313
1414 -- usage:
77 add '?/init.server'
88
99 require 'mmm'
10 import load_tree from require 'mmm.mmmfs.fileder'
10 import Fileder from require 'mmm.mmmfs.fileder'
1111 import get_store from require 'mmm.mmmfs.stores'
1212 import render from require 'mmm.mmmfs.layout'
1313
1919 STATIC = true
2020
2121 store = get_store store
22 tree = load_tree store
22 tree = Fileder store
2323 tree = tree\walk startpath if startpath
2424
2525 for fileder in coroutine.wrap tree\iterate
88
99 require 'mmm'
1010
11 import Key, dir_base, load_tree from require 'mmm.mmmfs.fileder'
11 import dir_base, Key, Fileder from require 'mmm.mmmfs.fileder'
1212 import convert from require 'mmm.mmmfs.conversion'
1313 import get_store from require 'mmm.mmmfs.stores'
1414 import render from require 'mmm.mmmfs.layout'
3737 assert @server\loop!
3838
3939 handle: (method, path, facet) =>
40 fileder = load_tree @store, path -- @tree\walk path
40 fileder = Fileder @store, path
4141
4242 if not fileder
4343 -- fileder not found
4949 when '?interactive'
5050 export BROWSER
5151
52 root = load_tree @store
52 root = Fileder @store
5353 BROWSER = Browser root, path
5454 render BROWSER\todom!, fileder, noview: true, scripts: "
5555 <script type=\"application/lua\">
214214 with select :onchange
215215 \append option '(none)', value: '', disabled: true, selected: not value
216216 if fileder
217 for key, _ in pairs fileder.facets
217 for i, key in ipairs fileder\get_facets!
218218 value = key\tostring!
219219 \append option value, :value, selected: value == current
220220 @inspect\map (enabled) ->
00 require = relative ..., 1
11 import get_conversions, apply_conversions from require '.conversion'
2
3 -- split filename into dirname + basename
4 dir_base = (path) ->
5 dir, base = path\match '(.-)([^/]-)$'
6 if dir and #dir > 0
7 dir = dir\sub 1, #dir - 1
8
9 dir, base
210
311 -- Key of a Fileder Facet
412 -- contains:
3745 -- * @facets - Facet Map (Key to Value)
3846 -- * @children - Children Array
3947 class Fileder
40 -- instantiate from facets and children tables
41 -- or mix in one table (numeric keys are children, remainder facets)
42 -- facet-keys are passed to Key constructor
43 new: (facets, children) =>
44 if not children
45 children = for i, child in ipairs facets
46 facets[i] = nil
47 child
48
48 new: (@store, @path='') =>
49 @loaded = false
50
51 -- lazy-load children,
52 -- allow indexing by name as well as numeric index,
4953 -- automatically mount children on insert
5054 @children = setmetatable {}, {
55 __len: (t) ->
56 @load! unless @loaded
57 rawlen t
58
59 __ipairs: (t) ->
60 @load! unless @loaded
61 ipairs t
62
5163 __index: (t, k) ->
52 return rawget t, k unless 'string' == type k
53
54 @walk "#{@path}/#{k}"
64 @load! unless @loaded
65
66 if 'string' == type k
67 @walk "#{@path}/#{k}"
68 else
69 rawget t, k
5570
5671 __newindex: (t, k, child) ->
5772 rawset t, k, child
73
5874 if @path == '/'
5975 child\mount '/'
6076 elseif @path
6177 child\mount @path .. '/'
6278 }
6379
64 -- copy children
65 for i, child in ipairs children
66 @children[i] = child
67
68 -- automatically reify string keys on insert
69 @facets = setmetatable {}, __newindex: (t, key, v) ->
70 rawset t, (Key key), v
71
72 -- copy facets
73 for k, v in pairs facets
74 @facets[k] = v
80 -- lazy-load facets,
81 -- allow indexing by name as well as numeric index,
82 -- automatically mount children on insert
83
84 -- we need to store the presence of facets separately from the actual (cached) value,
85 -- because we want to lazily load the tree (index) *and* facet contents.
86 -- @facet_keys maps from key-strings to Key instances ('canonical Key instances')
87 -- @facets maps from canonical keys to cached values and lazy-loads.
88 -- both maps automatically rewrite __index and __newindex for both Key instances and strings.
89 @facet_keys = setmetatable {}, {
90 __pairs: (t) ->
91 @load! unless @loaded
92 next, t
93
94 __index: (t, k) ->
95 canonical = rawget t, tostring k
96 canonical or= Key k
97 canonical
98
99 __newindex: (t, k, v) ->
100 k = Key k
101 rawset t, (tostring k), v
102 }
103 @facets = setmetatable {}, {
104 __index: (t, k) ->
105 @load! unless @loaded
106
107 -- get canonical Key instance
108 k = @facet_keys[k]
109
110 -- if cached, return
111 if v = rawget t, k
112 return v
113
114 with v = @store\load_facet @path, k.name, k.type
115 rawset t, k, v
116
117 __pairs: (t) ->
118 @load! unless @loaded
119
120 -- force cache all facets
121 for k, v in pairs @facet_keys
122 t[v]
123
124 pairs @facets
125
126 __newindex: (t, k, v) ->
127 -- get canonical Key instance
128 k = @facet_keys[k]
129
130 rawset t, k, v
131
132 v = k unless v == nil
133 rawset @facet_keys, k, v
134 }
135
136 load: =>
137 @loaded = true
138
139 for path in @store\list_fileders_in @path
140 table.insert @children, Fileder @store, path
141
142 for name, type in @store\list_facets @path
143 key = Key name, type
144 @facet_keys[key] = key
145
146 _, name = dir_base @path
147 @facets['name: alpha'] = name
148
149 -- -- instantiate from facets and children tables
150 -- -- or mix in one table (numeric keys are children, remainder facets)
151 -- -- facet-keys are passed to Key constructor
152 -- new: (facets, children) =>
153 -- if not children
154 -- children = for i, child in ipairs facets
155 -- facets[i] = nil
156 -- child
157
158 -- -- automatically mount children on insert
159 -- @children = setmetatable {}, {
160 -- __index: (t, k) ->
161 -- return rawget t, k unless 'string' == type k
162
163 -- @walk "#{@path}/#{k}"
164
165 -- __newindex: (t, k, child) ->
166 -- rawset t, k, child
167 -- if @path == '/'
168 -- child\mount '/'
169 -- elseif @path
170 -- child\mount @path .. '/'
171 -- }
172
173 -- -- copy children
174 -- for i, child in ipairs children
175 -- @children[i] = child
176
177 -- -- automatically reify string keys on insert
178 -- @facets = setmetatable {}, __newindex: (t, key, v) ->
179 -- rawset t, (Key key), v
180
181 -- -- copy facets
182 -- for k, v in pairs facets
183 -- @facets[k] = v
75184
76185 -- recursively walk to and return the fileder with @path == path
77186 -- * path - the path to walk to
116225 -- get all facet names (list)
117226 get_facets: =>
118227 names = {}
119 for key in pairs @facets
228 for str, key in pairs @facet_keys
120229 names[key.name] = true
121230
122231 [name for name in pairs names]
123232
233 -- get an index table, listing path, facets and children
234 -- optionally get recursive index
124235 get_index: (recursive=false) =>
125236 {
126237 path: @path
127 facets: [{k.name, k.type} for k,v in pairs @facets]
238 facets: [key for str, key in pairs @facet_keys]
128239 children: if recursive
129240 [child\get_index true for child in *@children]
130241 else
132243 }
133244
134245 -- check whether a facet is directly available
135 -- when passing a Key, set type to false to check for name only
136246 has: (...) =>
137247 want = Key ...
138248
139 for key in pairs @facets
140 continue if key.original
141
142 if key.name == want.name and key.type == want.type
143 return key
249 @facet_keys[want]
144250
145251 -- check whether any facet with that name exists
146252 has_facet: (want) =>
147 for key in pairs @facets
253 for str, key in pairs @facet_keys
148254 continue if key.original
149255
150256 if key.name == want
156262 want = Key ...
157263
158264 -- filter facets by name
159 matching = [ key for key in pairs @facets when key.name == want.name ]
265 matching = [ key for str, key in pairs @facet_keys when key.name == want.name ]
160266 return unless #matching > 0
161267
162268 -- get shortest conversion path
191297
192298 __tostring: => "Fileder:#{@path}"
193299
194 -- split filename into dirname + basename
195 dir_base = (path) ->
196 dir, base = path\match '(.-)([^/]-)$'
197 if dir and #dir > 0
198 dir = dir\sub 1, #dir - 1
199
200 dir, base
201
202 -- load tree from a store instance
203 -- optionally load subtree starting at 'root' path
204 load_tree = (store, root='') ->
205 fileders = setmetatable {},
206 __index: (path) =>
207 with val = Fileder {}
208 .path = path
209 rawset @, path, val
210
211 root = fileders[root]
212 root.facets['name: alpha'] = ''
213 for fn, ft in store\list_facets root.path
214 val = store\load_facet root.path, fn, ft
215 root.facets[Key fn, ft] = val
216
217 for path in store\list_all_fileders root.path
218 fileder = fileders[path]
219
220 parent, name = dir_base path
221 fileder.facets['name: alpha'] = name
222 table.insert fileders[parent].children, fileder
223
224 for fn, ft in store\list_facets path
225 val = store\load_facet path, fn, ft
226 fileder.facets[Key fn, ft] = val
227
228 root
229
230300 {
231301 :Key
232302 :Fileder
233303 :dir_base
234 :load_tree
235304 }
0 import elements from require 'mmm.component'
1 import h1, h2, p, a, i, div, ol, li, br, hr, span, button, section, article from elements
2
3 _content = div!
4 append = _content\append
5
6 if MODE == 'SERVER'
7 export ^
8 class Diagram
9 style = {
10 display: 'inline-block',
11 width: '150px',
12 height: '80px',
13 'line-height': '80px',
14 color: '#fff',
15 background: '#666',
16 }
17
18 @id = 1
19 new: (@func) =>
20 @id = "diagram-#{@@id}"
21 @@id += 1
22
23 render: =>
24 rplc = with div id: @id, :style
25 \append '(diagram goes here)'
26 -- \append "<script type=\"application/lua\">
27 -- local rplc = js.global.document:getElementById('#{@id}');
28 -- local fn = #{compile @func}
29 -- diag = Diagram(fn)
30 -- rplc.parentNode:replaceChild(diag.node, rplc)
31 -- </script>"
32 rplc\render!
33
34 if MODE == 'CLIENT'
35 export ^
36 export o
37 eval = js.global\eval
38 GRID_W = 50
39 GRID_H = 40
40
41 SVG =
42 doc: eval "(function() { return SVG(document.createElement('svg')); })",
43 G: eval "(function() { return new SVG.G(); })",
44 setmetatable SVG, __call: => @doc!
45
46 o = do
47 mkobj = eval "(function () { return {}; })"
48 (tbl) ->
49 with obj = mkobj!
50 for k,v in pairs(tbl)
51 obj[k] = v
52
53 class Diagram
54 new: (f) =>
55 @svg = SVG!
56 @arrows = SVG.G!
57 @width, @height = 0, 0
58 @y = 0
59
60 f @
61
62 txtattr = o {
63 fill: 'white',
64 'font-size': '14px',
65 'text-anchor': 'middle',
66 }
67 block: (color, label, h=1) =>
68 @svg\add with SVG.G!
69 with \rect GRID_W, h * GRID_H
70 \attr o fill: color
71 if label
72 with \plain label
73 \move GRID_W/2, 0
74 \attr txtattr
75
76 \move @width * GRID_W, (@y + h) * -GRID_H
77 @y += h
78 if @y > @height
79 @height = @y
80
81 arrattr = o {
82 fill: 'white',
83 'font-size': '18px',
84 'text-anchor': 'middle',
85 }
86 arrow: (char, x, y) =>
87 with @arrows\plain char
88 \attr arrattr
89 \move (x + 1) * GRID_W, (y - 0.5) * -GRID_H - 11
90
91 -- inout: (x=@width, y=@y) => @arrow '⇋', x, y -- U+21CB
92 -- inn: (x=@width, y=@y) => @arrow '↼', x, y+0.25 -- U+21BC
93 -- out: (x=@width, y=@y) => @arrow '⇁', x, y-0.25 -- U+21C1
94 inout: (x=@width, y=@y) => @arrow '⇆', x, y -- U+21C6
95 inn: (x=@width, y=@y) => @arrow '←', x, y+0.25 -- U+2190
96 out: (x=@width, y=@y) => @arrow '→', x, y-0.25 -- U+2192
97
98 mind: (label='mind', ...) => @block '#fac710', label, ...
99 phys: (label='phys', ...) => @block '#8fd13f', label, ...
100 digi: (label='digi', ...) => @block '#9510ac', label, ...
101
102 next: =>
103 @y = 0
104 @width += 1
105
106 finish: =>
107 return if @node
108 @svg\add @arrows
109
110 @width += 1
111 w, h = @width * GRID_W, @height * GRID_H
112
113 l = GRID_W / 6.5
114 @svg\add with @svg\line 0, -GRID_H, w, -GRID_H
115 \stroke o width: 2, color: '#ffffff', dasharray: "#{l}, #{l}"
116
117 @svg\size w, h
118 @svg\viewbox 0, -h, w, h
119 @node = @svg.node
120
121 addlabel = (label, diagram) ->
122 with div style: { display: 'inline-block', margin: '20px', 'text-align': 'center' }
123 \append diagram
124 \append div label
125
126 figures = do
127 style =
128 display: 'flex'
129 'align-items': 'flex-end'
130 'justify-content': 'space-evenly'
131 (...) -> div { :style, ... }
132
133 sources = do
134 short = => "#{@id} #{@year}"
135 long = => @names, " (#{@year}): ", (i @title), ", #{@published}"
136 {
137 {
138 id: 'Milgram',
139 title: 'Augmented Reality: A class of displays on the reality-virtuality continuum',
140 published: 'in SPIE Vol. 2351',
141 names: 'P. Milgram, H. Takemura, A. Utsumi, F. Kishino',
142 year: 1994
143 :long, :short,
144 },
145 {
146 id: 'Marsh',
147 title: 'Nested Immersion: Describing and Classifying Augmented Virtual Reality',
148 published: 'IEEE Virtual Reality Conference 2015',
149 names: 'W. Marsh, F. Mérienne',
150 year: 2015
151 :long, :short,
152 },
153 {
154 id: 'Billinghurst',
155 title: 'The MagicBook: a transitional AR interface',
156 published: 'in Computer & Graphics 25',
157 names: 'M. Billinghurst, H. Kato, I. Poupyrev',
158 year: 2001,
159 :long, :short,
160 },
161 {
162 id: 'Matrix',
163 title: 'The Matrix',
164 year: 1999,
165 names: 'L. Wachowski, A. Wachowski',
166 long: => @names, " (#{@year}): ", (i @title), " (movie)"
167 short: => tostring @year
168 },
169 {
170 id: 'Naam',
171 title: 'Nexus',
172 published: 'Angry Robot (novel)',
173 names: 'R. Naam',
174 year: 2012,
175 :long, :short,
176 }
177 }
178
179 ref = do
180 fmt = (id) ->
181
182 local src
183 for _src in *sources
184 if _src.id == id
185 src = _src
186 break
187
188 if src
189 a { src\short!, href: "##{src.id}" }
190 else
191 span id
192
193 ref = (...) ->
194 refs = { ... }
195 with span "(", fmt refs[1]
196 for i=2, #refs
197 \append ", "
198 \append fmt refs[i]
199 \append ")"
200
201 references = ->
202 with ol!
203 for src in *sources
204 \append li { id: src.id, src\long! }
205
206 sect = (label) ->
207 with section style: 'page-break-inside': 'avoid'
208 \append h2 label
209
210 append with article style: { margin: 'auto', 'max-width': '750px' }
211 \append div 'Sol Bekic', style: 'text-align': 'right'
212
213 \append h1 {
214 style: { 'text-align': 'center', 'font-size': '2em' },
215 "Reality Stacks",
216 div "a Taxonomy for Multi-Reality Experiences", style: 'font-size': '0.6em'
217 }
218
219 \append with sect "Abstract"
220 \append p "With the development of mixed-reality experiences and the corresponding interface devices
221 multiple frameworks for classification of these experiences have been proposed. However these past
222 attempts have mostly been developed alongside and with the intent of capturing specific projects ",
223 (ref 'Marsh', 'Billinghurst'), " or are nevertheless very focused on existing methods and technologies ",
224 (ref 'Milgram'), ". The existing taxonomies also all assume physical reality as a fixpoint and constant and are
225 thereby not suited to describe many fictional mixed-reality environments and altered states of consciousness.
226 In this paper we describe a new model for describing such experiences and examplify it's use with currently
227 existing as well as idealized technologies from popular culture."
228
229 \append with sect "Terminology"
230 \append p "We propose the following terms and definitions that will be used extensively for the remainder of the paper:"
231 for definition in *{
232 { "layer of reality": "a closed system consisting of a world model and a set of rules or dynamics operating on and
233 constraining said model." },
234 { "world model": "describes a world state containing objects, agents and/or concepts on an arbitrary abstraction level." },
235 '------',
236 { "reality stack": "structure consisting of all layers of reality encoding an agent's interaction with his environment
237 in their world model at a given moment, as well as all layers supporting these respectively." },
238 '------',
239 { "physical reality": "layer of reality defined by physical matter and the physical laws acting upon it.
240 While the emergent phenomena of micro- and macro physics as well as layers of social existence etc. may be seen
241 as separate layers, for the purpose of this paper we will group these together under the term of physical reality." },
242 { "mental reality": "layer of reality perceived and processed by the brain of a human agent." },
243 { "digital reality": "layer of reality created and simulated by a digital system, e.g. a virtual reality game." },
244 { "phys, mind, digi": "abbreviations for physical, mental and digital reality respectively." },
245 }
246 if 'string' == type definition
247 \append hr!
248 continue
249 \append with div style: { 'margin-left': '2rem' }
250 term = next definition
251 \append span term, style: {
252 display: 'inline-block',
253 'margin-left': '-2rem',
254 'font-weight': 'bold',
255 'min-width': '140px'
256 }
257 \append span definition[term]
258
259 \append with sect "Introduction"
260 \append p "We identify two different types of relationships between layers in multi-reality environments.
261 The first is layer nesting. Layer nesting describes how some layers are contained in other layers; i.e. they exist
262 within and can be represented fully by the parent layer's world model and the child layer's rules emerge natively from
263 the parent layer's dynamics. Layer nesting is visualized on the vertical axis in the following diagrams.
264 For each layer of reality on the bottom of the diagram the nested parent layers can be found by tracing a line upwards
265 to the top of the diagram. Following a materialistic point of view, physical reality therefore must completely encompass
266 the top of each diagram."
267
268 \append p "The second type of relationship describes the information flow between a subject and the layers of reality
269 the subject is immersed in. In a multi-reality experience the subject has access to multiple layers of reality and
270 their corresponding world models simultaneously.", br!,
271 "Depending on the specific experience, different types of and directions for information exchange
272 can exist between these layers and the subject's internal representation of the experience.
273 For the sake of this paper we distinguish only between ", (i "input"), " and ", (i "output"), " data flow (from the
274 perspective of the subject); categorized loosely as information the subject receives from the environment
275 (", (i "input"), ", e.g. visual stimuli) and actions the subject can take to influence the state of the world model
276 (", (i "output"), ", e.g. motor actions) respectively."
277
278 \append p "In the following diagrams, information flow is visualized horizontally, in the region below the dashed line
279 at the bottom of the diagram. The subject's internal mental model and layer of reality are placed on the bottom left
280 side of the diagram.
281 The layers of reality that the subject experiences directly and that mirror it's internal representations are placed
282 on the far right. There may be multiple layers of reality sharing this space, visualized as a vertical stack of
283 layers. Since the subject must necessarily have a complete internal model of the multi-reality experience around
284 him to feel immersed, the subject's mental layer of reality must span the full height of all the layers visible
285 on the right side of the diagram.", br!,
286 "Information flow itself is now visualized concretely using arrows that cross layer boundaries in the lower part of
287 the diagram as described above. Arrows pointing leftwards denote ", (i "input"), " flow, whilst arrows pointing
288 rightwards denote ", (i "output"), "-directed information flow. In some cases information doesn't flow directly
289 between the layers the subject is directly aware of and the subject's internal representation and instead
290 traverses ", (i "intermediate layers"), " first."
291
292 \append p "Before we take a look at some reality stacks corresponding to current VR and AR technology,
293 we can take a look at waking life as a baseline stack. To illustrate the format of the diagram we will compare it
294 to the stack corresponding to a dreaming state:"
295
296 \append with figures!
297 \append addlabel "Waking Life", Diagram =>
298 @mind!
299 @inout!
300 @phys!
301
302 @next!
303 @phys '', 2
304 @finish!
305
306 \append addlabel "Dreaming", Diagram =>
307 @mind!
308 @phys!
309 @finish!
310
311 \append p "In both cases, the top of the diagram is fully occupied by the physical layer of reality, colored in green.
312 This is due to the fact that, according to the materialistic theory of mind, human consciousness owes its existance
313 to the physical and chemical dynamics of neurons in our brains. Therefore our mental reality must be considered
314 fully embedded in the physical reality, and consequently it may only appear underneath it in the diagram."
315
316 \append p "During waking life, we concern ourselves mostly with the physical reality surrounding us.
317 For this reason the physical reality is placed in the lower right corner of the diagram as the layer holding the
318 external world model relevant to the subject. Information flows in both directions between the physical world model
319 and the subject's mental model, as denoted by the two white arrows: Information about the state of the world model
320 enter the subjects mind via the senses (top arrow, pointing leftwards), and choices the subject makes inside of and
321 based on his mental model can feed back into the physical layer through movements (lower arrow, pointing rightwards)."
322
323 \append p "In the dreaming state on the other hand, the subject is unaware of the physical layer of reality, though
324 the mind remains embedded inside it. When dreaming, subjects' mental models don't depend on external models, hence
325 the mental layer of reality must be the only layer along the bottom of the diagram."
326
327 \append with sect "Current Technologies"
328 \append p "Since recent technological advancements have enabled the development of VR and AR consumer devices,
329 AR and VR have been established as the potential next frontier of digital entertainment.", br!,
330 "As the names imply, the notion of reality is at the core of both technologies.
331 In the following section we will take a look at the respective stacks of both experience types:"
332
333 \append with figures!
334 \append addlabel "VR", Diagram =>
335 @mind!
336 @phys!
337 @inout nil, 1
338
339 @next!
340 @phys '', 2
341 @inout nil, 1
342
343 @next!
344 @digi!
345 @phys ''
346 @finish!
347
348
349 \append addlabel "AR", Diagram =>
350 @mind!
351 @inout nil, 1.25
352 @inn nil, 0.5
353 @phys!
354
355 @next!
356 @phys '', 2
357 @inn nil, .5
358
359 @next!
360 @digi nil, .5
361 @phys '', 1.5
362 @finish!
363
364 \append p "In both cases we find the physical layer of reality as an ", (i "intermediate layer"), " between the mental
365 and digital layers. Actions taken by the subject have to be acted out physically (corresponding to the
366 information traversing the barrier between mental and physical reality) before they can be again digitized using
367 the various tracking and input technologies (which in turn carry the information across the boundary of the physical
368 and digital spaces)."
369
370 \append p "The difference between AR and VR lies in the fact that in AR the subject experiences a mixture of the
371 digital and physical world models. This can be seen in the diagram, where we find that right of the diagram origin
372 and the mental model, the diagram splits and terminates in both layers: while information reaches the subject both
373 from the digital reality through the physical one, as well as directly from the physical reality, the subject only
374 directly manipulates state in the physical reality."
375
376 \append p "The data conversions necessary at layer boundaries incur at the least losses in quality and accuracy of
377 information for purely technical reasons. However ", (i "intermediate layers"), " come at a cost larger than just
378 an additional step of conversion:
379 For information to flow through a layer, it must be encodable within that layer’s world model.
380 This means that the 'weakest link' in a given reality stack determines the upper bound of information possible to
381 encode within said stack and thereby limits the overall expressivity of the stack.", br!,
382 "As a practical example we can consider creating an hypothetical VR application that allows users to traverse a
383 large virtual space by flying. While the human mind is perfectly capable of imagining to fly and control the motion
384 appropriately, it is extremely hard to devise and implement a satisfying setup and control scheme because the
385 physical body of the user needs to be taken into account and it, unlike the corresponding representations in the
386 mental and digital world models, cannot float around freely."
387
388 \append with sect "Future Developments"
389 \append p "In the previous section we found that the presence of the physical layer in the information path of
390 VR and AR stacks limits the experience as a whole. It follows that the removal of that indirection should be
391 an obvious goal for future developments:"
392
393 \append figures addlabel "holy grail of VR: 'The Matrix'", Diagram =>
394 @mind!
395 @inout!
396 @phys!
397
398 @next!
399 @digi!
400 @phys ''
401 @finish!
402
403 \append p "In the action movie 'The Matrix' ", (ref 'Matrix'), ", users of the titular VR environment interface with it
404 by plugging cables into implanted sockets that connect the simulation directly to their central nervous system.", br!,
405 "While these cables and implanted devices are physical devices, they don't constitute the presence of the
406 physical layer of reality in the information path because while they do transmit information, the information
407 remains in either the encoding of the mental model (neural firing patterns) or the encoding of the digital model
408 (e.g. a numeric encoding of a player character's movement in digital space) and the conversion is made directly
409 between those two - the data never assumes the native encoding of the physical layer (e.g. as a physical motion)."
410
411 \append p "While we are currently far from being able to read arbitrary high-level information from the brain
412 or to synthesize sensual input in human perception by bypassing the sensory organs, brain-computer interfaces (BCI)
413 are a very active area of research with high hopes for comparable achievements in the near future."
414
415 \append p "Applying this same step of removing the physical layer of reality from AR, we end up with something similar
416 to the nano-particle drug in ", (i "Nexus"), " ", (ref 'Naam'), ". However this does not grant the user a similar
417 amount of control over his experience as the holy grail of VR does, since the user and the physical part of the
418 environment remain bound by the physical layer of reality's laws.", br!,
419 "Instead the holy grail of AR is reached with the creation of a god machine that can manipulate the state of the
420 physical world according to the user's wishes. In this way the digital and physical realities become unified and
421 fully 'augmented'."
422
423 \append with figures!
424 \append addlabel "'Nexus'", Diagram =>
425 @mind!
426 @inout nil, 0.75
427 @inout nil, 1.25
428 @phys!
429
430 @next!
431 @digi nil, .5
432 @phys '', 1.5
433 @finish!
434
435 \append addlabel "holy grail of AR: 'Deus Machina'", Diagram =>
436 col = '#92807c'
437
438 @mind!
439 @inout!
440 @block col, ''
441
442 @next!
443 @block col, '', 2
444 @svg\plain('phys + digi')\attr(o fill: 'white', 'font-size': '14px')\move 6, -2 * GRID_H
445 @finish!
446
447 \append p "Despite the similarities of VR and AR, the two can be considered polar opposites, as becomes evident when
448 we compare their respective utopian implementations: they share the goal of allowing us to experience realities
449 different from the one we naturally inhabit, but while VR seeks to accomplish this by creating a new, nested reality
450 inside ours, thus giving us full control over it.
451 AR, on the other hand, is instead an attempt to retrofit our specific needs directly into the very reality we exist
452 in.", br!,
453 "This is in direct contrast with the popular notion of the 'reality-virtuality continuum' ", (ref 'Milgram'), ":
454 the reality-virtuality continuum places common reality and VR (virtuality) as the two extreme poles, while AR
455 is represented as an intermediate state between the two. Here however we propose to view instead AR and VR as the
456 respective poles and find instead reality at the centerpoint, where the two opposing influences 'cancel out'."
457
458 \append with sect "Conclusion and Further Work"
459 \append p "In this paper we have proposed a taxonomy and visualization style for multi-reality experiences, as well
460 as demonstrated it's flexibility by applying them as examples. Through the application of the proposed theory,
461 we have also gained a new and contrasting view on preceding work such as the reality-virtuality-continuum.
462 We have also found that the taxonomy can be used outside the research field of media studies and its use may extend
463 as far as philosophy of consciousness (see Appendix below)."
464
465 \append p "Further research could enhance the proposed theory with better and more concrete definitions.
466 In the future, the proposed taxonomy might be used to create a more extensive and complete classification
467 of reality stacks and to analyse the relationships between them."
468
469 \append with sect 'References'
470 \append references!
471
472 \append with sect "Appendix: Relation to Theories of Mind"
473 \append p "This paper starts from a deeply materialistic point of view that borders on microphysicalism.
474 However it should be noted that the diagram style introduced above lends itself also to display other
475 philosophical theories of mind. As an example, the following graphics show a typical VR stack as interpreted by
476 Materialism, Cartesian Dualism and Solipsism respectively:"
477
478 \append with figures!
479 \append addlabel "VR in Materialism", Diagram =>
480 @mind!
481 @inout nil, 1
482 @phys!
483
484 @next!
485 @phys '', 2
486 @inout nil, 1
487
488 @next!
489 @digi!
490 @phys ''
491
492 @finish!
493
494 \append addlabel "VR in Solipsism", Diagram =>
495 @mind nil, 2
496 @inout nil, 1
497
498 @next!
499 @digi!
500 @mind ''
501 @finish!
502
503 \append addlabel "VR in Cartesian Dualism", Diagram =>
504 @mind nil, 2
505 @inout nil, 1
506 @next!
507
508 @phys nil, 2
509 @inout nil, 1
510 @next!
511
512 @digi!
513 @phys ''
514 @finish!
515
516 \append p "However these philosophical theories of minds also constitute reality stacks by themselves and as such can
517 be compared directly:"
518
519 \append with figures!
520 \append addlabel "Materialism", Diagram =>
521 @mind!
522 @inout!
523 @phys!
524
525 @next!
526 @phys '', 2
527 @finish!
528
529 \append addlabel "Solipsism", Diagram =>
530 @mind!
531 @finish!
532
533 \append addlabel "Cartesian Dualism", Diagram =>
534 @mind!
535 @inout!
536 @next!
537
538 @phys!
539 @finish!
540
541 _content
+0
-542
root/articles/realities/text$moonscript -> mmm$dom.moon less more
0 import elements from require 'mmm.component'
1 import h1, h2, p, a, i, div, ol, li, br, hr, span, button, section, article from elements
2
3 _content = div!
4 append = _content\append
5
6 if MODE == 'SERVER'
7 export ^
8 class Diagram
9 style = {
10 display: 'inline-block',
11 width: '150px',
12 height: '80px',
13 'line-height': '80px',
14 color: '#fff',
15 background: '#666',
16 }
17
18 @id = 1
19 new: (@func) =>
20 @id = "diagram-#{@@id}"
21 @@id += 1
22
23 render: =>
24 rplc = with div id: @id, :style
25 \append '(diagram goes here)'
26 -- \append "<script type=\"application/lua\">
27 -- local rplc = js.global.document:getElementById('#{@id}');
28 -- local fn = #{compile @func}
29 -- diag = Diagram(fn)
30 -- rplc.parentNode:replaceChild(diag.node, rplc)
31 -- </script>"
32 rplc\render!
33
34 if MODE == 'CLIENT'
35 export ^
36 export o
37 eval = js.global\eval
38 GRID_W = 50
39 GRID_H = 40
40
41 SVG =
42 doc: eval "(function() { return SVG(document.createElement('svg')); })",
43 G: eval "(function() { return new SVG.G(); })",
44 setmetatable SVG, __call: => @doc!
45
46 o = do
47 mkobj = eval "(function () { return {}; })"
48 (tbl) ->
49 with obj = mkobj!
50 for k,v in pairs(tbl)
51 obj[k] = v
52
53 class Diagram
54 new: (f) =>
55 @svg = SVG!
56 @arrows = SVG.G!
57 @width, @height = 0, 0
58 @y = 0
59
60 f @
61
62 txtattr = o {
63 fill: 'white',
64 'font-size': '14px',
65 'text-anchor': 'middle',
66 }
67 block: (color, label, h=1) =>
68 @svg\add with SVG.G!
69 with \rect GRID_W, h * GRID_H
70 \attr o fill: color
71 if label
72 with \plain label
73 \move GRID_W/2, 0
74 \attr txtattr
75
76 \move @width * GRID_W, (@y + h) * -GRID_H
77 @y += h
78 if @y > @height
79 @height = @y
80
81 arrattr = o {
82 fill: 'white',
83 'font-size': '18px',
84 'text-anchor': 'middle',
85 }
86 arrow: (char, x, y) =>
87 with @arrows\plain char
88 \attr arrattr
89 \move (x + 1) * GRID_W, (y - 0.5) * -GRID_H - 11
90
91 -- inout: (x=@width, y=@y) => @arrow '⇋', x, y -- U+21CB
92 -- inn: (x=@width, y=@y) => @arrow '↼', x, y+0.25 -- U+21BC
93 -- out: (x=@width, y=@y) => @arrow '⇁', x, y-0.25 -- U+21C1
94 inout: (x=@width, y=@y) => @arrow '⇆', x, y -- U+21C6
95 inn: (x=@width, y=@y) => @arrow '←', x, y+0.25 -- U+2190
96 out: (x=@width, y=@y) => @arrow '→', x, y-0.25 -- U+2192
97
98 mind: (label='mind', ...) => @block '#fac710', label, ...
99 phys: (label='phys', ...) => @block '#8fd13f', label, ...
100 digi: (label='digi', ...) => @block '#9510ac', label, ...
101
102 next: =>
103 @y = 0
104 @width += 1
105
106 finish: =>
107 return if @node
108 @svg\add @arrows
109
110 @width += 1
111 w, h = @width * GRID_W, @height * GRID_H
112
113 l = GRID_W / 6.5
114 @svg\add with @svg\line 0, -GRID_H, w, -GRID_H
115 \stroke o width: 2, color: '#ffffff', dasharray: "#{l}, #{l}"
116
117 @svg\size w, h
118 @svg\viewbox 0, -h, w, h
119 @node = @svg.node
120
121 addlabel = (label, diagram) ->
122 with div style: { display: 'inline-block', margin: '20px', 'text-align': 'center' }
123 \append diagram
124 \append div label
125
126 figures = do
127 style =
128 display: 'flex'
129 'align-items': 'flex-end'
130 'justify-content': 'space-evenly'
131 (...) -> div { :style, ... }
132
133 sources = do
134 short = => "#{@id} #{@year}"
135 long = => @names, " (#{@year}): ", (i @title), ", #{@published}"
136 {
137 {
138 id: 'Milgram',
139 title: 'Augmented Reality: A class of displays on the reality-virtuality continuum',
140 published: 'in SPIE Vol. 2351',
141 names: 'P. Milgram, H. Takemura, A. Utsumi, F. Kishino',
142 year: 1994
143 :long, :short,
144 },
145 {
146 id: 'Marsh',
147 title: 'Nested Immersion: Describing and Classifying Augmented Virtual Reality',
148 published: 'IEEE Virtual Reality Conference 2015',
149 names: 'W. Marsh, F. Mérienne',
150 year: 2015
151 :long, :short,
152 },
153 {
154 id: 'Billinghurst',
155 title: 'The MagicBook: a transitional AR interface',
156 published: 'in Computer & Graphics 25',
157 names: 'M. Billinghurst, H. Kato, I. Poupyrev',
158 year: 2001,
159 :long, :short,
160 },
161 {
162 id: 'Matrix',
163 title: 'The Matrix',
164 year: 1999,
165 names: 'L. Wachowski, A. Wachowski',
166 long: => @names, " (#{@year}): ", (i @title), " (movie)"
167 short: => tostring @year
168 },
169 {
170 id: 'Naam',
171 title: 'Nexus',
172 published: 'Angry Robot (novel)',
173 names: 'R. Naam',
174 year: 2012,
175 :long, :short,
176 }
177 }
178
179 ref = do
180 fmt = (id) ->
181
182 local src
183 for _src in *sources
184 if _src.id == id
185 src = _src
186 break
187
188 if src
189 a { src\short!, href: "##{src.id}" }
190 else
191 span id
192
193 ref = (...) ->
194 refs = { ... }
195 with span "(", fmt refs[1]
196 for i=2, #refs
197 \append ", "
198 \append fmt refs[i]
199 \append ")"
200
201 references = ->
202 with ol!
203 for src in *sources
204 \append li { id: src.id, src\long! }
205
206 sect = (label) ->
207 with section style: 'page-break-inside': 'avoid'
208 \append h2 label
209
210 append with article style: { margin: 'auto', 'max-width': '750px' }
211 \append div 'Sol Bekic', style: 'text-align': 'right'
212
213 \append h1 {
214 style: { 'text-align': 'center', 'font-size': '2em' },
215 "Reality Stacks",
216 div "a Taxonomy for Multi-Reality Experiences", style: 'font-size': '0.6em'
217 }
218
219 \append with sect "Abstract"
220 \append p "With the development of mixed-reality experiences and the corresponding interface devices
221 multiple frameworks for classification of these experiences have been proposed. However these past
222 attempts have mostly been developed alongside and with the intent of capturing specific projects ",
223 (ref 'Marsh', 'Billinghurst'), " or are nevertheless very focused on existing methods and technologies ",
224 (ref 'Milgram'), ". The existing taxonomies also all assume physical reality as a fixpoint and constant and are
225 thereby not suited to describe many fictional mixed-reality environments and altered states of consciousness.
226 In this paper we describe a new model for describing such experiences and examplify it's use with currently
227 existing as well as idealized technologies from popular culture."
228
229 \append with sect "Terminology"
230 \append p "We propose the following terms and definitions that will be used extensively for the remainder of the paper:"
231 for definition in *{
232 { "layer of reality": "a closed system consisting of a world model and a set of rules or dynamics operating on and
233 constraining said model." },
234 { "world model": "describes a world state containing objects, agents and/or concepts on an arbitrary abstraction level." },
235 '------',
236 { "reality stack": "structure consisting of all layers of reality encoding an agent's interaction with his environment
237 in their world model at a given moment, as well as all layers supporting these respectively." },
238 '------',
239 { "physical reality": "layer of reality defined by physical matter and the physical laws acting upon it.
240 While the emergent phenomena of micro- and macro physics as well as layers of social existence etc. may be seen
241 as separate layers, for the purpose of this paper we will group these together under the term of physical reality." },
242 { "mental reality": "layer of reality perceived and processed by the brain of a human agent." },
243 { "digital reality": "layer of reality created and simulated by a digital system, e.g. a virtual reality game." },
244 { "phys, mind, digi": "abbreviations for physical, mental and digital reality respectively." },
245 }
246 if 'string' == type definition
247 \append hr!
248 continue
249 \append with div style: { 'margin-left': '2rem' }
250 term = next definition
251 \append span term, style: {
252 display: 'inline-block',
253 'margin-left': '-2rem',
254 'font-weight': 'bold',
255 'min-width': '140px'
256 }
257 \append span definition[term]
258
259 \append with sect "Introduction"
260 \append p "We identify two different types of relationships between layers in multi-reality environments.
261 The first is layer nesting. Layer nesting describes how some layers are contained in other layers; i.e. they exist
262 within and can be represented fully by the parent layer's world model and the child layer's rules emerge natively from
263 the parent layer's dynamics. Layer nesting is visualized on the vertical axis in the following diagrams.
264 For each layer of reality on the bottom of the diagram the nested parent layers can be found by tracing a line upwards
265 to the top of the diagram. Following a materialistic point of view, physical reality therefore must completely encompass
266 the top of each diagram."
267
268 \append p "The second type of relationship describes the information flow between a subject and the layers of reality
269 the subject is immersed in. In a multi-reality experience the subject has access to multiple layers of reality and
270 their corresponding world models simultaneously.", br!,
271 "Depending on the specific experience, different types of and directions for information exchange
272 can exist between these layers and the subject's internal representation of the experience.
273 For the sake of this paper we distinguish only between ", (i "input"), " and ", (i "output"), " data flow (from the
274 perspective of the subject); categorized loosely as information the subject receives from the environment
275 (", (i "input"), ", e.g. visual stimuli) and actions the subject can take to influence the state of the world model
276 (", (i "output"), ", e.g. motor actions) respectively."
277
278 \append p "In the following diagrams, information flow is visualized horizontally, in the region below the dashed line
279 at the bottom of the diagram. The subject's internal mental model and layer of reality are placed on the bottom left
280 side of the diagram.
281 The layers of reality that the subject experiences directly and that mirror it's internal representations are placed
282 on the far right. There may be multiple layers of reality sharing this space, visualized as a vertical stack of
283 layers. Since the subject must necessarily have a complete internal model of the multi-reality experience around
284 him to feel immersed, the subject's mental layer of reality must span the full height of all the layers visible
285 on the right side of the diagram.", br!,
286 "Information flow itself is now visualized concretely using arrows that cross layer boundaries in the lower part of
287 the diagram as described above. Arrows pointing leftwards denote ", (i "input"), " flow, whilst arrows pointing
288 rightwards denote ", (i "output"), "-directed information flow. In some cases information doesn't flow directly
289 between the layers the subject is directly aware of and the subject's internal representation and instead
290 traverses ", (i "intermediate layers"), " first."
291
292 \append p "Before we take a look at some reality stacks corresponding to current VR and AR technology,
293 we can take a look at waking life as a baseline stack. To illustrate the format of the diagram we will compare it
294 to the stack corresponding to a dreaming state:"
295
296 \append with figures!
297 \append addlabel "Waking Life", Diagram =>
298 @mind!
299 @inout!
300 @phys!
301
302 @next!
303 @phys '', 2
304 @finish!
305
306 \append addlabel "Dreaming", Diagram =>
307 @mind!
308 @phys!
309 @finish!
310
311 \append p "In both cases, the top of the diagram is fully occupied by the physical layer of reality, colored in green.
312 This is due to the fact that, according to the materialistic theory of mind, human consciousness owes its existance
313 to the physical and chemical dynamics of neurons in our brains. Therefore our mental reality must be considered
314 fully embedded in the physical reality, and consequently it may only appear underneath it in the diagram."
315
316 \append p "During waking life, we concern ourselves mostly with the physical reality surrounding us.
317 For this reason the physical reality is placed in the lower right corner of the diagram as the layer holding the
318 external world model relevant to the subject. Information flows in both directions between the physical world model
319 and the subject's mental model, as denoted by the two white arrows: Information about the state of the world model
320 enter the subjects mind via the senses (top arrow, pointing leftwards), and choices the subject makes inside of and
321 based on his mental model can feed back into the physical layer through movements (lower arrow, pointing rightwards)."
322
323 \append p "In the dreaming state on the other hand, the subject is unaware of the physical layer of reality, though
324 the mind remains embedded inside it. When dreaming, subjects' mental models don't depend on external models, hence
325 the mental layer of reality must be the only layer along the bottom of the diagram."
326
327 \append with sect "Current Technologies"
328 \append p "Since recent technological advancements have enabled the development of VR and AR consumer devices,
329 AR and VR have been established as the potential next frontier of digital entertainment.", br!,
330 "As the names imply, the notion of reality is at the core of both technologies.
331 In the following section we will take a look at the respective stacks of both experience types:"
332
333 \append with figures!
334 \append addlabel "VR", Diagram =>
335 @mind!
336 @phys!
337 @inout nil, 1
338
339 @next!
340 @phys '', 2
341 @inout nil, 1
342
343 @next!
344 @digi!
345 @phys ''
346 @finish!
347
348
349 \append addlabel "AR", Diagram =>
350 @mind!
351 @inout nil, 1.25
352 @inn nil, 0.5
353 @phys!
354
355 @next!
356 @phys '', 2
357 @inn nil, .5
358
359 @next!
360 @digi nil, .5
361 @phys '', 1.5
362 @finish!
363
364 \append p "In both cases we find the physical layer of reality as an ", (i "intermediate layer"), " between the mental
365 and digital layers. Actions taken by the subject have to be acted out physically (corresponding to the
366 information traversing the barrier between mental and physical reality) before they can be again digitized using
367 the various tracking and input technologies (which in turn carry the information across the boundary of the physical
368 and digital spaces)."
369
370 \append p "The difference between AR and VR lies in the fact that in AR the subject experiences a mixture of the
371 digital and physical world models. This can be seen in the diagram, where we find that right of the diagram origin
372 and the mental model, the diagram splits and terminates in both layers: while information reaches the subject both
373 from the digital reality through the physical one, as well as directly from the physical reality, the subject only
374 directly manipulates state in the physical reality."
375
376 \append p "The data conversions necessary at layer boundaries incur at the least losses in quality and accuracy of
377 information for purely technical reasons. However ", (i "intermediate layers"), " come at a cost larger than just
378 an additional step of conversion:
379 For information to flow through a layer, it must be encodable within that layer’s world model.
380 This means that the 'weakest link' in a given reality stack determines the upper bound of information possible to
381 encode within said stack and thereby limits the overall expressivity of the stack.", br!,
382 "As a practical example we can consider creating an hypothetical VR application that allows users to traverse a
383 large virtual space by flying. While the human mind is perfectly capable of imagining to fly and control the motion
384 appropriately, it is extremely hard to devise and implement a satisfying setup and control scheme because the
385 physical body of the user needs to be taken into account and it, unlike the corresponding representations in the
386 mental and digital world models, cannot float around freely."
387
388 \append with sect "Future Developments"
389 \append p "In the previous section we found that the presence of the physical layer in the information path of
390 VR and AR stacks limits the experience as a whole. It follows that the removal of that indirection should be
391 an obvious goal for future developments:"
392
393 \append figures addlabel "holy grail of VR: 'The Matrix'", Diagram =>
394 @mind!
395 @inout!
396 @phys!
397
398 @next!
399 @digi!
400 @phys ''
401 @finish!
402
403 \append p "In the action movie 'The Matrix' ", (ref 'Matrix'), ", users of the titular VR environment interface with it
404 by plugging cables into implanted sockets that connect the simulation directly to their central nervous system.", br!,
405 "While these cables and implanted devices are physical devices, they don't constitute the presence of the
406 physical layer of reality in the information path because while they do transmit information, the information
407 remains in either the encoding of the mental model (neural firing patterns) or the encoding of the digital model
408 (e.g. a numeric encoding of a player character's movement in digital space) and the conversion is made directly
409 between those two - the data never assumes the native encoding of the physical layer (e.g. as a physical motion)."
410
411 \append p "While we are currently far from being able to read arbitrary high-level information from the brain
412 or to synthesize sensual input in human perception by bypassing the sensory organs, brain-computer interfaces (BCI)
413 are a very active area of research with high hopes for comparable achievements in the near future."
414
415 \append p "Applying this same step of removing the physical layer of reality from AR, we end up with something similar
416 to the nano-particle drug in ", (i "Nexus"), " ", (ref 'Naam'), ". However this does not grant the user a similar
417 amount of control over his experience as the holy grail of VR does, since the user and the physical part of the
418 environment remain bound by the physical layer of reality's laws.", br!,
419 "Instead the holy grail of AR is reached with the creation of a god machine that can manipulate the state of the
420 physical world according to the user's wishes. In this way the digital and physical realities become unified and
421 fully 'augmented'."
422
423 \append with figures!
424 \append addlabel "'Nexus'", Diagram =>
425 @mind!
426 @inout nil, 0.75
427 @inout nil, 1.25
428 @phys!
429
430 @next!
431 @digi nil, .5
432 @phys '', 1.5
433 @finish!
434
435 \append addlabel "holy grail of AR: 'Deus Machina'", Diagram =>
436 col = '#92807c'
437
438 @mind!
439 @inout!
440 @block col, ''
441
442 @next!
443 @block col, '', 2
444 @svg\plain('phys + digi')\attr(o fill: 'white', 'font-size': '14px')\move 6, -2 * GRID_H
445 @finish!
446
447 \append p "Despite the similarities of VR and AR, the two can be considered polar opposites, as becomes evident when
448 we compare their respective utopian implementations: they share the goal of allowing us to experience realities
449 different from the one we naturally inhabit, but while VR seeks to accomplish this by creating a new, nested reality
450 inside ours, thus giving us full control over it.
451 AR, on the other hand, is instead an attempt to retrofit our specific needs directly into the very reality we exist
452 in.", br!,
453 "This is in direct contrast with the popular notion of the 'reality-virtuality continuum' ", (ref 'Milgram'), ":
454 the reality-virtuality continuum places common reality and VR (virtuality) as the two extreme poles, while AR
455 is represented as an intermediate state between the two. Here however we propose to view instead AR and VR as the
456 respective poles and find instead reality at the centerpoint, where the two opposing influences 'cancel out'."
457
458 \append with sect "Conclusion and Further Work"
459 \append p "In this paper we have proposed a taxonomy and visualization style for multi-reality experiences, as well
460 as demonstrated it's flexibility by applying them as examples. Through the application of the proposed theory,
461 we have also gained a new and contrasting view on preceding work such as the reality-virtuality-continuum.
462 We have also found that the taxonomy can be used outside the research field of media studies and its use may extend
463 as far as philosophy of consciousness (see Appendix below)."
464
465 \append p "Further research could enhance the proposed theory with better and more concrete definitions.
466 In the future, the proposed taxonomy might be used to create a more extensive and complete classification
467 of reality stacks and to analyse the relationships between them."
468
469 \append with sect 'References'
470 \append references!
471
472 \append with sect "Appendix: Relation to Theories of Mind"
473 \append p "This paper starts from a deeply materialistic point of view that borders on microphysicalism.
474 However it should be noted that the diagram style introduced above lends itself also to display other
475 philosophical theories of mind. As an example, the following graphics show a typical VR stack as interpreted by
476 Materialism, Cartesian Dualism and Solipsism respectively:"
477
478 \append with figures!
479 \append addlabel "VR in Materialism", Diagram =>
480 @mind!
481 @inout nil, 1
482 @phys!
483
484 @next!
485 @phys '', 2
486 @inout nil, 1
487
488 @next!
489 @digi!
490 @phys ''
491
492 @finish!
493
494 \append addlabel "VR in Solipsism", Diagram =>
495 @mind nil, 2
496 @inout nil, 1
497
498 @next!
499 @digi!
500 @mind ''
501 @finish!
502
503 \append addlabel "VR in Cartesian Dualism", Diagram =>
504 @mind nil, 2
505 @inout nil, 1
506 @next!
507
508 @phys nil, 2
509 @inout nil, 1
510 @next!
511
512 @digi!
513 @phys ''
514 @finish!
515
516 \append p "However these philosophical theories of minds also constitute reality stacks by themselves and as such can
517 be compared directly:"
518
519 \append with figures!
520 \append addlabel "Materialism", Diagram =>
521 @mind!
522 @inout!
523 @phys!
524
525 @next!
526 @phys '', 2
527 @finish!
528
529 \append addlabel "Solipsism", Diagram =>
530 @mind!
531 @finish!
532
533 \append addlabel "Cartesian Dualism", Diagram =>
534 @mind!
535 @inout!
536 @next!
537
538 @phys!
539 @finish!
540
541 _content
1414 demo = tohtml example!
1515
1616 div the_code, div demo, class: 'example'
17
18 raw_find = (fileder, key_pat) ->
19 for key, val in pairs fileder.facets
20 return val if key\tostring!\match key_pat
2117
2218 =>
2319 example = (name) ->
0 local p = package.preload
1 if not p["mmm.canvasapp"] then p["mmm.canvasapp"] = load("local window = js.global\
2 local js = require('js')\
3 local a, canvas, div, button, script\
4 do\
5 local _obj_0 = require('mmm.dom')\
6 a, canvas, div, button, script = _obj_0.a, _obj_0.canvas, _obj_0.div, _obj_0.button, _obj_0.script\
7 end\
8 local CanvasApp\
9 do\
10 local _class_0\
11 local _base_0 = {\
12 width = 500,\
13 height = 400,\
14 update = function(self, dt)\
15 self.time = self.time + dt\
16 if self.length and self.time > self.length then\
17 self.time = self.time - self.length\
18 return true\
19 end\
20 end,\
21 render = function(self, fps)\
22 if fps == nil then\
23 fps = 60\
24 end\
25 assert(self.length, 'cannot render CanvasApp without length set')\
26 self.paused = true\
27 local actual_render\
28 actual_render = function()\
29 local writer = js.new(window.Whammy.Video, fps)\
30 local doFrame\
31 doFrame = function()\
32 local done = self:update(1 / fps)\
33 self.ctx:resetTransform()\
34 self:draw()\
35 writer:add(self.canvas)\
36 if done or self.time >= self.length then\
37 local blob = writer:compile()\
38 local name = tostring(self.__class.__name) .. \"_\" .. tostring(fps) .. \"fps.webm\"\
39 return self.node.lastChild:appendChild(a(name, {\
40 download = name,\
41 href = window.URL:createObjectURL(blob)\
42 }))\
43 else\
44 return window:setTimeout(doFrame)\
45 end\
46 end\
47 self.time = 0\
48 return doFrame()\
49 end\
50 if window.Whammy then\
51 return actual_render()\
52 else\
53 window.global = window.global or window\
54 return document.body:appendChild(script({\
55 onload = actual_render,\
56 src = 'https://cdn.jsdelivr.net/npm/whammy@0.0.1/whammy.min.js'\
57 }))\
58 end\
59 end\
60 }\
61 _base_0.__index = _base_0\
62 _class_0 = setmetatable({\
63 __init = function(self, show_menu, paused)\
64 if show_menu == nil then\
65 show_menu = false\
66 end\
67 self.paused = paused\
68 self.canvas = canvas({\
69 width = self.width,\
70 height = self.height\
71 })\
72 self.ctx = self.canvas:getContext('2d')\
73 self.time = 0\
74 self.canvas.tabIndex = 0\
75 self.canvas:addEventListener('click', function(_, e)\
76 return self.click and self:click(e.offsetX, e.offsetY, e.button)\
77 end)\
78 self.canvas:addEventListener('keydown', function(_, e)\
79 return self.keydown and self:keydown(e.key, e.code)\
80 end)\
81 local lastMillis = window.performance:now()\
82 local animationFrame\
83 animationFrame = function(_, millis)\
84 self:update((millis - lastMillis) / 1000)\
85 self.ctx:resetTransform()\
86 self:draw()\
87 lastMillis = millis\
88 if not self.paused then\
89 return window:setTimeout((function()\
90 return window:requestAnimationFrame(animationFrame)\
91 end), 0)\
92 end\
93 end\
94 window:requestAnimationFrame(animationFrame)\
95 if show_menu then\
96 self.node = div({\
97 className = 'canvas_app',\
98 self.canvas,\
99 div({\
100 className = 'overlay',\
101 button('render 30fps', {\
102 onclick = function()\
103 return self:render(30)\
104 end\
105 }),\
106 button('render 60fps', {\
107 onclick = function()\
108 return self:render(60)\
109 end\
110 })\
111 })\
112 })\
113 else\
114 self.node = self.canvas\
115 end\
116 end,\
117 __base = _base_0,\
118 __name = \"CanvasApp\"\
119 }, {\
120 __index = _base_0,\
121 __call = function(cls, ...)\
122 local _self_0 = setmetatable({}, _base_0)\
123 cls.__init(_self_0, ...)\
124 return _self_0\
125 end\
126 })\
127 _base_0.__class = _class_0\
128 CanvasApp = _class_0\
129 end\
130 return {\
131 CanvasApp = CanvasApp\
132 }\
133 ", "mmm/canvasapp.client.lua") end
134 if not p["mmm.color"] then p["mmm.color"] = load("local rgb\
135 rgb = function(r, g, b)\
136 if 'table' == type(r) then\
137 r, g, b = table.unpack(r)\
138 end\
139 return \"rgb(\" .. tostring(r * 255) .. \", \" .. tostring(g * 255) .. \", \" .. tostring(b * 255) .. \")\"\
140 end\
141 local rgba\
142 rgba = function(r, g, b, a)\
143 if 'table' == type(r) then\
144 r, g, b, a = table.unpack(r)\
145 end\
146 return \"rgba(\" .. tostring(r * 255) .. \", \" .. tostring(g * 255) .. \", \" .. tostring(b * 255) .. \", \" .. tostring(a or 1) .. \")\"\
147 end\
148 local hsl\
149 hsl = function(h, s, l)\
150 if 'table' == type(h) then\
151 h, s, l = table.unpack(h)\
152 end\
153 return \"hsl(\" .. tostring(h * 360) .. \", \" .. tostring(s * 100) .. \"%, \" .. tostring(l * 100) .. \"%)\"\
154 end\
155 local hsla\
156 hsla = function(h, s, l, a)\
157 if 'table' == type(h) then\
158 h, s, l, a = table.unpack(h)\
159 end\
160 return \"hsla(\" .. tostring(h * 360) .. \", \" .. tostring(s * 100) .. \"%, \" .. tostring(l * 100) .. \"%, \" .. tostring(a or 1) .. \")\"\
161 end\
162 return {\
163 rgb = rgb,\
164 rgba = rgba,\
165 hsl = hsl,\
166 hsla = hsla\
167 }\
168 ", "mmm/color.lua") end
169 if not p["mmm.highlighting"] then p["mmm.highlighting"] = load("local code\
170 code = require('mmm.dom').code\
171 local highlight\
172 local trim\
173 trim = function(str)\
174 return str:match('^ *(..-) *$')\
175 end\
176 if MODE == 'SERVER' then\
177 highlight = function(lang, str)\
178 assert(str, 'no string to highlight')\
179 return code((trim(str)), {\
180 class = \"hljs lang-\" .. tostring(lang)\
181 })\
182 end\
183 else\
184 highlight = function(lang, str)\
185 assert(str, 'no string to highlight')\
186 local result = window.hljs:highlight(lang, (trim(str)), true)\
187 do\
188 local _with_0 = code({\
189 class = \"hljs lang-\" .. tostring(lang)\
190 })\
191 _with_0.innerHTML = result.value\
192 return _with_0\
193 end\
194 end\
195 end\
196 local languages = setmetatable({ }, {\
197 __index = function(self, name)\
198 do\
199 local val\
200 val = function(str)\
201 return highlight(name, str)\
202 end\
203 self[name] = val\
204 return val\
205 end\
206 end\
207 })\
208 return {\
209 highlight = highlight,\
210 languages = languages\
211 }\
212 ", "mmm/highlighting.lua") end
213 if not p["mmm"] then p["mmm"] = load("window = js.global\
214 local console\
215 document, console = window.document, window.console\
216 MODE = 'CLIENT'\
217 local deep_tostring\
218 deep_tostring = function(tbl, space)\
219 if space == nil then\
220 space = ''\
221 end\
222 if 'userdata' == type(tbl) then\
223 return tbl\
224 end\
225 local buf = space .. tostring(tbl)\
226 if not ('table' == type(tbl)) then\
227 return buf\
228 end\
229 buf = buf .. ' {\\n'\
230 for k, v in pairs(tbl) do\
231 buf = buf .. tostring(space) .. \" [\" .. tostring(k) .. \"]: \" .. tostring(deep_tostring(v, space .. ' ')) .. \"\\n\"\
232 end\
233 buf = buf .. tostring(space) .. \"}\"\
234 return buf\
235 end\
236 print = function(...)\
237 local contents\
238 do\
239 local _accum_0 = { }\
240 local _len_0 = 1\
241 local _list_0 = {\
242 ...\
243 }\
244 for _index_0 = 1, #_list_0 do\
245 local v = _list_0[_index_0]\
246 _accum_0[_len_0] = deep_tostring(v)\
247 _len_0 = _len_0 + 1\
248 end\
249 contents = _accum_0\
250 end\
251 return console:log(table.unpack(contents))\
252 end\
253 warn = function(...)\
254 local contents\
255 do\
256 local _accum_0 = { }\
257 local _len_0 = 1\
258 local _list_0 = {\
259 ...\
260 }\
261 for _index_0 = 1, #_list_0 do\
262 local v = _list_0[_index_0]\
263 _accum_0[_len_0] = deep_tostring(v)\
264 _len_0 = _len_0 + 1\
265 end\
266 contents = _accum_0\
267 end\
268 return console:warn(table.unpack(contents))\
269 end\
270 package.path = '/?.lua;/?/init.lua'\
271 do\
272 local _require = require\
273 relative = function(base, sub)\
274 if not ('number' == type(sub)) then\
275 sub = 0\
276 end\
277 for i = 1, sub do\
278 base = base:match('^(.*)%.%w+$')\
279 end\
280 return function(name, x)\
281 if '.' == name:sub(1, 1) then\
282 name = base .. name\
283 end\
284 return _require(name)\
285 end\
286 end\
287 end\
288 if on_load then\
289 for _index_0 = 1, #on_load do\
290 local f = on_load[_index_0]\
291 f()\
292 end\
293 end\
294 on_load = setmetatable({ }, {\
295 __newindex = function(t, k, v)\
296 rawset(t, k, v)\
297 return v()\
298 end\
299 })\
300 ", "mmm/init.client.lua") end
301 if not p["mmm.ordered"] then p["mmm.ordered"] = load("local sort\
302 sort = function(t, order_fn, only_strings)\
303 do\
304 local index\
305 do\
306 local _accum_0 = { }\
307 local _len_0 = 1\
308 for k, v in pairs(t) do\
309 if (not only_strings) or 'string' == type(k) then\
310 _accum_0[_len_0] = k\
311 _len_0 = _len_0 + 1\
312 end\
313 end\
314 index = _accum_0\
315 end\
316 table.sort(index, order_fn)\
317 return index\
318 end\
319 end\
320 local onext\
321 onext = function(state, key)\
322 state.i = state.i + state.step\
323 local t, index, i\
324 t, index, i = state.t, state.index, state.i\
325 do\
326 key = index[i]\
327 if key then\
328 return key, t[key]\
329 end\
330 end\
331 end\
332 local opairs\
333 opairs = function(t, order_fn, only_strings)\
334 if only_strings == nil then\
335 only_strings = false\
336 end\
337 local state = {\
338 t = t,\
339 i = 0,\
340 step = 1,\
341 index = sort(t, order_fn, only_strings)\
342 }\
343 return onext, state, nil\
344 end\
345 local ropairs\
346 ropairs = function(t, order_fn, only_strings)\
347 if only_strings == nil then\
348 only_strings = false\
349 end\
350 local index = sort(t, order_fn, only_strings)\
351 local state = {\
352 t = t,\
353 index = index,\
354 i = #index + 1,\
355 step = -1\
356 }\
357 return onext, state, nil\
358 end\
359 return {\
360 onext = onext,\
361 opairs = opairs,\
362 ropairs = ropairs\
363 }\
364 ", "mmm/ordered.lua") end
365 if not p["mmm.mmmfs.browser"] then p["mmm.mmmfs.browser"] = load("local require = relative(..., 1)\
366 local Key\
367 Key = require('.fileder').Key\
368 local converts, get_conversions, apply_conversions\
369 do\
370 local _obj_0 = require('.conversion')\
371 converts, get_conversions, apply_conversions = _obj_0.converts, _obj_0.get_conversions, _obj_0.apply_conversions\
372 end\
373 local ReactiveVar, get_or_create, text, elements\
374 do\
375 local _obj_0 = require('mmm.component')\
376 ReactiveVar, get_or_create, text, elements = _obj_0.ReactiveVar, _obj_0.get_or_create, _obj_0.text, _obj_0.elements\
377 end\
378 local pre, div, nav, span, button, a, code, select, option\
379 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\
380 local languages\
381 languages = require('mmm.highlighting').languages\
382 local keep\
383 keep = function(var)\
384 local last = var:get()\
385 return var:map(function(val)\
386 last = val or last\
387 return last\
388 end)\
389 end\
390 local code_cast\
391 code_cast = function(lang)\
392 return {\
393 inp = \"text/\" .. tostring(lang) .. \".*\",\
394 out = 'mmm/dom',\
395 transform = function(val)\
396 return languages[lang](val)\
397 end\
398 }\
399 end\
400 local casts = {\
401 code_cast('javascript'),\
402 code_cast('moonscript'),\
403 code_cast('lua'),\
404 code_cast('markdown'),\
405 code_cast('html'),\
406 {\
407 inp = 'text/plain',\
408 out = 'mmm/dom',\
409 transform = function(val)\
410 return text(val)\
411 end\
412 },\
413 {\
414 inp = 'URL.*',\
415 out = 'mmm/dom',\
416 transform = function(href)\
417 return span(a((code(href)), {\
418 href = href\
419 }))\
420 end\
421 }\
422 }\
423 for _index_0 = 1, #converts do\
424 local convert = converts[_index_0]\
425 table.insert(casts, convert)\
426 end\
427 local Browser\
428 do\
429 local _class_0\
430 local err_and_trace, default_convert\
431 local _base_0 = {\
432 get_content = function(self, prop, err, convert)\
433 if err == nil then\
434 err = self.error\
435 end\
436 if convert == nil then\
437 convert = default_convert\
438 end\
439 local clear_error\
440 clear_error = function()\
441 if MODE == 'CLIENT' then\
442 return err:set()\
443 end\
444 end\
445 local disp_error\
446 disp_error = function(msg)\
447 if MODE == 'CLIENT' then\
448 err:set(pre(msg))\
449 end\
450 warn(\"ERROR rendering content: \" .. tostring(msg))\
451 return nil\
452 end\
453 local active = self.active:get()\
454 if not (active) then\
455 return disp_error(\"fileder not found!\")\
456 end\
457 if not (prop) then\
458 return disp_error(\"facet not found!\")\
459 end\
460 local ok, res = xpcall(convert, err_and_trace, active, prop)\
461 if MODE == 'CLIENT' then\
462 document.body.classList:remove('loading')\
463 end\
464 if ok and res then\
465 clear_error()\
466 return res\
467 elseif ok then\
468 return div(\"[no conversion path to \" .. tostring(prop.type) .. \"]\")\
469 elseif res and res.msg.match and res.msg:match('%[nossr%]$') then\
470 return div(\"[this page could not be pre-rendered on the server]\")\
471 else\
472 res = tostring(res.msg) .. \"\\n\" .. tostring(res.trace)\
473 return disp_error(res)\
474 end\
475 end,\
476 get_inspector = function(self)\
477 self.inspect_prop = self.facet:map(function(prop)\
478 local active = self.active:get()\
479 local key = active and active:find(prop)\
480 if key and key.original then\
481 key = key.original\
482 end\
483 return key\
484 end)\
485 self.inspect_err = ReactiveVar()\
486 do\
487 local _with_0 = div({\
488 class = 'view inspector'\
489 })\
490 _with_0:append(nav({\
491 span('inspector'),\
492 self.inspect_prop:map(function(current)\
493 current = current and current:tostring()\
494 local fileder = self.active:get()\
495 local onchange\
496 onchange = function(_, e)\
497 if e.target.value == '' then\
498 return \
499 end\
500 local name\
501 name = self.facet:get().name\
502 return self.inspect_prop:set(Key(e.target.value))\
503 end\
504 do\
505 local _with_1 = select({\
506 onchange = onchange\
507 })\
508 _with_1:append(option('(none)', {\
509 value = '',\
510 disabled = true,\
511 selected = not value\
512 }))\
513 if fileder then\
514 for key, _ in pairs(fileder.facets) do\
515 local value = key:tostring()\
516 _with_1:append(option(value, {\
517 value = value,\
518 selected = value == current\
519 }))\
520 end\
521 end\
522 return _with_1\
523 end\
524 end),\
525 self.inspect:map(function(enabled)\
526 if enabled then\
527 return button('close', {\
528 onclick = function(_, e)\
529 return self.inspect:set(false)\
530 end\
531 })\
532 end\
533 end)\
534 }))\
535 _with_0:append((function()\
536 do\
537 local _with_1 = div({\
538 class = self.inspect_err:map(function(e)\
539 if e then\
540 return 'error-wrap'\
541 else\
542 return 'error-wrap empty'\
543 end\
544 end)\
545 })\
546 _with_1:append(span(\"an error occured while rendering this view:\"))\
547 _with_1:append(self.inspect_err)\
548 return _with_1\
549 end\
550 end)())\
551 _with_0:append((function()\
552 do\
553 local _with_1 = pre({\
554 class = 'content'\
555 })\
556 _with_1:append(keep(self.inspect_prop:map(function(prop, old)\
557 return self:get_content(prop, self.inspect_err, function(self, prop)\
558 local value, key = self:get(prop)\
559 assert(key, \"couldn't @get \" .. tostring(prop))\
560 local conversions = get_conversions('mmm/dom', key.type, casts)\
561 assert(conversions, \"cannot cast '\" .. tostring(key.type) .. \"'\")\
562 return apply_conversions(conversions, value, self, prop)\
563 end)\
564 end)))\
565 return _with_1\
566 end\
567 end)())\
568 return _with_0\
569 end\
570 end,\
571 navigate = function(self, new)\
572 return self.path:set(new)\
573 end\
574 }\
575 _base_0.__index = _base_0\
576 _class_0 = setmetatable({\
577 __init = function(self, root, path, rehydrate)\
578 if rehydrate == nil then\
579 rehydrate = false\
580 end\
581 self.root = root\
582 assert(self.root, 'root fileder is nil')\
583 self.path = ReactiveVar(path or '')\
584 if MODE == 'CLIENT' then\
585 local logo = document:querySelector('header h1 > svg')\
586 local spin\
587 spin = function()\
588 logo.classList:add('spin')\
589 local _ = logo.parentElement.offsetWidth\
590 return logo.classList:remove('spin')\
591 end\
592 self.path:subscribe(function(path)\
593 document.body.classList:add('loading')\
594 spin()\
595 if self.skip then\
596 return \
597 end\
598 local vis_path = path .. ((function()\
599 if '/' == path:sub(-1) then\
600 return ''\
601 else\
602 return '/'\
603 end\
604 end)())\
605 return window.history:pushState(path, '', vis_path)\
606 end)\
607 window.onpopstate = function(_, event)\
608 if event.state and not event.state == js.null then\
609 self.skip = true\
610 self.path:set(event.state)\
611 self.skip = nil\
612 end\
613 end\
614 end\
615 self.active = self.path:map((function()\
616 local _base_1 = self.root\
617 local _fn_0 = _base_1.walk\
618 return function(...)\
619 return _fn_0(_base_1, ...)\
620 end\
621 end)())\
622 self.facet = self.active:map(function(fileder)\
623 if not (fileder) then\
624 return \
625 end\
626 local last = self.facet and self.facet:get()\
627 return Key((function()\
628 if last then\
629 return last.type\
630 else\
631 return 'mmm/dom'\
632 end\
633 end)())\
634 end)\
635 self.inspect = ReactiveVar((MODE == 'CLIENT' and window.location.search:match('[?&]inspect')))\
636 local main = get_or_create('div', 'browser-root', {\
637 class = 'main view'\
638 })\
639 if MODE == 'SERVER' then\
640 main:append(nav({\
641 id = 'browser-navbar',\
642 span('please stand by... interactivity loading :)')\
643 }))\
644 else\
645 main:prepend((function()\
646 do\
647 local _with_0 = get_or_create('nav', 'browser-navbar')\
648 _with_0.node.innerHTML = ''\
649 _with_0:append(span('path: ', self.path:map(function(path)\
650 do\
651 local _with_1 = div({\
652 class = 'path',\
653 style = {\
654 display = 'inline-block'\
655 }\
656 })\
657 local path_segment\
658 path_segment = function(name, href)\
659 return a(name, {\
660 href = href,\
661 onclick = function(_, e)\
662 e:preventDefault()\
663 return self:navigate(href)\
664 end\
665 })\
666 end\
667 local href = ''\
668 path = path:match('^/(.*)')\
669 _with_1:append(path_segment('root', ''))\
670 while path do\
671 local name, rest = path:match('^([%w%-_%.]+)/(.*)')\
672 if not name then\
673 name = path\
674 end\
675 path = rest\
676 href = tostring(href) .. \"/\" .. tostring(name)\
677 _with_1:append('/')\
678 _with_1:append(path_segment(name, href))\
679 end\
680 return _with_1\
681 end\
682 end)))\
683 _with_0:append(span('view facet:', {\
684 style = {\
685 ['margin-right'] = '0'\
686 }\
687 }))\
688 _with_0:append(self.active:map(function(fileder)\
689 local onchange\
690 onchange = function(_, e)\
691 local type\
692 type = self.facet:get().type\
693 return self.facet:set(Key({\
694 name = e.target.value,\
695 type = type\
696 }))\
697 end\
698 local current = self.facet:get()\
699 current = current and current.name\
700 do\
701 local _with_1 = select({\
702 onchange = onchange,\
703 disabled = not fileder\
704 })\
705 local has_main = fileder and fileder:find(current.name, '.*')\
706 _with_1:append(option('(main)', {\
707 value = '',\
708 disabled = not has_main,\
709 selected = current == ''\
710 }))\
711 if fileder then\
712 for i, value in ipairs(fileder:get_facets()) do\
713 local _continue_0 = false\
714 repeat\
715 if value == '' then\
716 _continue_0 = true\
717 break\
718 end\
719 _with_1:append(option(value, {\
720 value = value,\
721 selected = value == current\
722 }))\
723 _continue_0 = true\
724 until true\
725 if not _continue_0 then\
726 break\
727 end\
728 end\
729 end\
730 return _with_1\
731 end\
732 end))\
733 _with_0:append(self.inspect:map(function(enabled)\
734 if not enabled then\
735 return button('inspect', {\
736 onclick = function(_, e)\
737 return self.inspect:set(true)\
738 end\
739 })\
740 end\
741 end))\
742 return _with_0\
743 end\
744 end)())\
745 end\
746 self.error = ReactiveVar()\
747 main:append((function()\
748 do\
749 local _with_0 = get_or_create('div', 'browser-error', {\
750 class = self.error:map(function(e)\
751 if e then\
752 return 'error-wrap'\
753 else\
754 return 'error-wrap empty'\
755 end\
756 end)\
757 })\
758 _with_0:append((span(\"an error occured while rendering this view:\")), (rehydrate and _with_0.node.firstChild))\
759 _with_0:append(self.error)\
760 return _with_0\
761 end\
762 end)())\
763 main:append((function()\
764 do\
765 local _with_0 = get_or_create('div', 'browser-content', {\
766 class = 'content'\
767 })\
768 local content = ReactiveVar((function()\
769 if rehydrate then\
770 return _with_0.node.lastChild\
771 else\
772 return self:get_content(self.facet:get())\
773 end\
774 end)())\
775 _with_0:append(keep(content))\
776 if MODE == 'CLIENT' then\
777 self.facet:subscribe(function(p)\
778 return window:setTimeout((function()\
779 return content:set(self:get_content(p))\
780 end), 150)\
781 end)\
782 end\
783 return _with_0\
784 end\
785 end)())\
786 if rehydrate then\
787 self.facet:set(self.facet:get())\
788 end\
789 local inspector = self.inspect:map(function(enabled)\
790 if enabled then\
791 return self:get_inspector()\
792 end\
793 end)\
794 local wrapper = get_or_create('div', 'browser-wrapper', main, inspector, {\
795 class = 'browser'\
796 })\
797 self.node = wrapper.node\
798 do\
799 local _base_1 = wrapper\
800 local _fn_0 = _base_1.render\
801 self.render = function(...)\
802 return _fn_0(_base_1, ...)\
803 end\
804 end\
805 end,\
806 __base = _base_0,\
807 __name = \"Browser\"\
808 }, {\
809 __index = _base_0,\
810 __call = function(cls, ...)\
811 local _self_0 = setmetatable({}, _base_0)\
812 cls.__init(_self_0, ...)\
813 return _self_0\
814 end\
815 })\
816 _base_0.__class = _class_0\
817 local self = _class_0\
818 err_and_trace = function(msg)\
819 return {\
820 msg = msg,\
821 trace = debug.traceback()\
822 }\
823 end\
824 default_convert = function(self, key)\
825 return self:get(key.name, 'mmm/dom')\
826 end\
827 default_convert = function(self, key)\
828 return self:get(key.name, 'mmm/dom')\
829 end\
830 Browser = _class_0\
831 end\
832 return {\
833 Browser = Browser\
834 }\
835 ", "mmm/mmmfs/browser.lua") end
836 if not p["mmm.mmmfs.conversion"] then p["mmm.mmmfs.conversion"] = load("local require = relative(..., 1)\
837 local converts = require('.converts')\
838 local count\
839 count = function(base, pattern)\
840 if pattern == nil then\
841 pattern = '->'\
842 end\
843 return select(2, base:gsub(pattern, ''))\
844 end\
845 local escape_pattern\
846 escape_pattern = function(inp)\
847 return \"^\" .. tostring(inp:gsub('([^%w])', '%%%1')) .. \"$\"\
848 end\
849 local escape_inp\
850 escape_inp = function(inp)\
851 return \"^\" .. tostring(inp:gsub('([-/])', '%%%1')) .. \"$\"\
852 end\
853 local get_conversions\
854 get_conversions = function(want, have, _converts, limit)\
855 if _converts == nil then\
856 _converts = converts\
857 end\
858 if limit == nil then\
859 limit = 5\
860 end\
861 assert(have, 'need starting type(s)')\
862 if 'string' == type(have) then\
863 have = {\
864 have\
865 }\
866 end\
867 assert(#have > 0, 'need starting type(s) (list was empty)')\
868 want = escape_pattern(want)\
869 local iterations = limit + math.max(table.unpack((function()\
870 local _accum_0 = { }\
871 local _len_0 = 1\
872 for _index_0 = 1, #have do\
873 local type = have[_index_0]\
874 _accum_0[_len_0] = count(type)\
875 _len_0 = _len_0 + 1\
876 end\
877 return _accum_0\
878 end)()))\
879 do\
880 local _accum_0 = { }\
881 local _len_0 = 1\
882 for _index_0 = 1, #have do\
883 local start = have[_index_0]\
884 _accum_0[_len_0] = {\
885 start = start,\
886 rest = start,\
887 conversions = { }\
888 }\
889 _len_0 = _len_0 + 1\
890 end\
891 have = _accum_0\
892 end\
893 for i = 1, iterations do\
894 local next_have, c = { }, 1\
895 for _index_0 = 1, #have do\
896 local _des_0 = have[_index_0]\
897 local start, rest, conversions\
898 start, rest, conversions = _des_0.start, _des_0.rest, _des_0.conversions\
899 if rest:match(want) then\
900 return conversions, start\
901 else\
902 for _index_1 = 1, #_converts do\
903 local _continue_0 = false\
904 repeat\
905 local convert = _converts[_index_1]\
906 local inp = escape_inp(convert.inp)\
907 if not (rest:match(inp)) then\
908 _continue_0 = true\
909 break\
910 end\
911 local result = rest:gsub(inp, convert.out)\
912 if result then\
913 next_have[c] = {\
914 start = start,\
915 rest = result,\
916 conversions = {\
917 {\
918 convert = convert,\
919 from = rest,\
920 to = result\
921 },\
922 table.unpack(conversions)\
923 }\
924 }\
925 c = c + 1\
926 end\
927 _continue_0 = true\
928 until true\
929 if not _continue_0 then\
930 break\
931 end\
932 end\
933 end\
934 end\
935 have = next_have\
936 if not (#have > 0) then\
937 return \
938 end\
939 end\
940 end\
941 local apply_conversions\
942 apply_conversions = function(conversions, value, ...)\
943 for i = #conversions, 1, -1 do\
944 local step = conversions[i]\
945 value = step.convert.transform(step, value, ...)\
946 end\
947 return value\
948 end\
949 return {\
950 converts = converts,\
951 get_conversions = get_conversions,\
952 apply_conversions = apply_conversions\
953 }\
954 ", "mmm/mmmfs/conversion.lua") end
955 if not p["mmm.mmmfs.fileder"] then p["mmm.mmmfs.fileder"] = load("local require = relative(..., 1)\
956 local get_conversions, apply_conversions\
957 do\
958 local _obj_0 = require('.conversion')\
959 get_conversions, apply_conversions = _obj_0.get_conversions, _obj_0.apply_conversions\
960 end\
961 local Key\
962 do\
963 local _class_0\
964 local _base_0 = {\
965 tostring = function(self)\
966 if self.name == '' then\
967 return self.type\
968 else\
969 return tostring(self.name) .. \": \" .. tostring(self.type)\
970 end\
971 end,\
972 __tostring = function(self)\
973 return self:tostring()\
974 end\
975 }\
976 _base_0.__index = _base_0\
977 _class_0 = setmetatable({\
978 __init = function(self, opts, second)\
979 if 'string' == type(second) then\
980 self.name, self.type = (opts or ''), second\
981 elseif 'string' == type(opts) then\
982 self.name, self.type = opts:match('^([%w-_]+): *(.+)$')\
983 if not self.name then\
984 self.name = ''\
985 self.type = opts\
986 end\
987 elseif 'table' == type(opts) then\
988 self.name = opts.name\
989 self.type = opts.type\
990 self.original = opts.original\
991 self.filename = opts.filename\
992 else\
993 return error(\"wrong argument type: \" .. tostring(type(opts)) .. \", \" .. tostring(type(second)))\
994 end\
995 end,\
996 __base = _base_0,\
997 __name = \"Key\"\
998 }, {\
999 __index = _base_0,\
1000 __call = function(cls, ...)\
1001 local _self_0 = setmetatable({}, _base_0)\
1002 cls.__init(_self_0, ...)\
1003 return _self_0\
1004 end\
1005 })\
1006 _base_0.__class = _class_0\
1007 Key = _class_0\
1008 end\
1009 local Fileder\
1010 do\
1011 local _class_0\
1012 local _base_0 = {\
1013 walk = function(self, path)\
1014 if path == '' then\
1015 return self\
1016 end\
1017 if '/' ~= path:sub(1, 1) then\
1018 path = tostring(self.path) .. \"/\" .. tostring(path)\
1019 end\
1020 if not (self.path == path:sub(1, #self.path)) then\
1021 return \
1022 end\
1023 if #path == #self.path then\
1024 return self\
1025 end\
1026 local _list_0 = self.children\
1027 for _index_0 = 1, #_list_0 do\
1028 local child = _list_0[_index_0]\
1029 do\
1030 local match = child:walk(path)\
1031 if match then\
1032 return match\
1033 end\
1034 end\
1035 end\
1036 end,\
1037 mount = function(self, path, mount_as)\
1038 if not mount_as then\
1039 path = path .. self:gett('name: alpha')\
1040 end\
1041 assert(not self.path or self.path == path, \"mounted twice: \" .. tostring(self.path) .. \" and now \" .. tostring(path))\
1042 self.path = path\
1043 local _list_0 = self.children\
1044 for _index_0 = 1, #_list_0 do\
1045 local child = _list_0[_index_0]\
1046 child:mount(self.path .. '/')\
1047 end\
1048 end,\
1049 iterate = function(self, depth)\
1050 if depth == nil then\
1051 depth = 0\
1052 end\
1053 coroutine.yield(self)\
1054 if depth == 1 then\
1055 return \
1056 end\
1057 local _list_0 = self.children\
1058 for _index_0 = 1, #_list_0 do\
1059 local child = _list_0[_index_0]\
1060 child:iterate(depth - 1)\
1061 end\
1062 end,\
1063 get_facets = function(self)\
1064 local names = { }\
1065 for key in pairs(self.facets) do\
1066 names[key.name] = true\
1067 end\
1068 local _accum_0 = { }\
1069 local _len_0 = 1\
1070 for name in pairs(names) do\
1071 _accum_0[_len_0] = name\
1072 _len_0 = _len_0 + 1\
1073 end\
1074 return _accum_0\
1075 end,\
1076 has = function(self, ...)\
1077 local want = Key(...)\
1078 for key in pairs(self.facets) do\
1079 local _continue_0 = false\
1080 repeat\
1081 if key.original then\
1082 _continue_0 = true\
1083 break\
1084 end\
1085 if key.name == want.name and key.type == want.type then\
1086 return key\
1087 end\
1088 _continue_0 = true\
1089 until true\
1090 if not _continue_0 then\
1091 break\
1092 end\
1093 end\
1094 end,\
1095 has_facet = function(self, want)\
1096 for key in pairs(self.facets) do\
1097 local _continue_0 = false\
1098 repeat\
1099 if key.original then\
1100 _continue_0 = true\
1101 break\
1102 end\
1103 if key.name == want then\
1104 return key\
1105 end\
1106 _continue_0 = true\
1107 until true\
1108 if not _continue_0 then\
1109 break\
1110 end\
1111 end\
1112 end,\
1113 find = function(self, ...)\
1114 local want = Key(...)\
1115 local matching\
1116 do\
1117 local _accum_0 = { }\
1118 local _len_0 = 1\
1119 for key in pairs(self.facets) do\
1120 if key.name == want.name then\
1121 _accum_0[_len_0] = key\
1122 _len_0 = _len_0 + 1\
1123 end\
1124 end\
1125 matching = _accum_0\
1126 end\
1127 if not (#matching > 0) then\
1128 return \
1129 end\
1130 local shortest_path, start = get_conversions(want.type, (function()\
1131 local _accum_0 = { }\
1132 local _len_0 = 1\
1133 for _index_0 = 1, #matching do\
1134 local key = matching[_index_0]\
1135 _accum_0[_len_0] = key.type\
1136 _len_0 = _len_0 + 1\
1137 end\
1138 return _accum_0\
1139 end)())\
1140 if start then\
1141 for _index_0 = 1, #matching do\
1142 local key = matching[_index_0]\
1143 if key.type == start then\
1144 return key, shortest_path\
1145 end\
1146 end\
1147 return error(\"couldn't find key after resolution?\")\
1148 end\
1149 end,\
1150 get = function(self, ...)\
1151 local want = Key(...)\
1152 local key, conversions = self:find(want)\
1153 if key then\
1154 local value = apply_conversions(conversions, self.facets[key], self, key)\
1155 return value, key\
1156 end\
1157 end,\
1158 gett = function(self, ...)\
1159 local want = Key(...)\
1160 local value, key = self:get(want)\
1161 assert(value, tostring(self) .. \" doesn't have value for '\" .. tostring(want) .. \"'\")\
1162 return value, key\
1163 end,\
1164 __tostring = function(self)\
1165 return \"Fileder:\" .. tostring(self.path)\
1166 end\
1167 }\
1168 _base_0.__index = _base_0\
1169 _class_0 = setmetatable({\
1170 __init = function(self, facets, children)\
1171 if not children then\
1172 do\
1173 local _accum_0 = { }\
1174 local _len_0 = 1\
1175 for i, child in ipairs(facets) do\
1176 facets[i] = nil\
1177 local _value_0 = child\
1178 _accum_0[_len_0] = _value_0\
1179 _len_0 = _len_0 + 1\
1180 end\
1181 children = _accum_0\
1182 end\
1183 end\
1184 self.children = setmetatable({ }, {\
1185 __index = function(t, k)\
1186 if not ('string' == type(k)) then\
1187 return rawget(t, k)\
1188 end\
1189 return self:walk(tostring(self.path) .. \"/\" .. tostring(k))\
1190 end,\
1191 __newindex = function(t, k, child)\
1192 rawset(t, k, child)\
1193 if self.path == '/' then\
1194 return child:mount('/')\
1195 elseif self.path then\
1196 return child:mount(self.path .. '/')\
1197 end\
1198 end\
1199 })\
1200 for i, child in ipairs(children) do\
1201 self.children[i] = child\
1202 end\
1203 self.facets = setmetatable({ }, {\
1204 __newindex = function(t, key, v)\
1205 return rawset(t, (Key(key)), v)\
1206 end\
1207 })\
1208 for k, v in pairs(facets) do\
1209 self.facets[k] = v\
1210 end\
1211 end,\
1212 __base = _base_0,\
1213 __name = \"Fileder\"\
1214 }, {\
1215 __index = _base_0,\
1216 __call = function(cls, ...)\
1217 local _self_0 = setmetatable({}, _base_0)\
1218 cls.__init(_self_0, ...)\
1219 return _self_0\
1220 end\
1221 })\
1222 _base_0.__class = _class_0\
1223 Fileder = _class_0\
1224 end\
1225 local dir_base\
1226 dir_base = function(path)\
1227 local dir, base = path:match('(.-)([^/]-)$')\
1228 if dir and #dir > 0 then\
1229 dir = dir:sub(1, #dir - 1)\
1230 end\
1231 return dir, base\
1232 end\
1233 local load_tree\
1234 load_tree = function(store, root)\
1235 if root == nil then\
1236 root = ''\
1237 end\
1238 local fileders = setmetatable({ }, {\
1239 __index = function(self, path)\
1240 do\
1241 local val = Fileder({ })\
1242 val.path = path\
1243 rawset(self, path, val)\
1244 return val\
1245 end\
1246 end\
1247 })\
1248 root = fileders[root]\
1249 root.facets['name: alpha'] = ''\
1250 for fn, ft in store:list_facets(root.path) do\
1251 local val = store:load_facet(root.path, fn, ft)\
1252 root.facets[Key(fn, ft)] = val\
1253 end\
1254 for path in store:list_all_fileders(root.path) do\
1255 local fileder = fileders[path]\
1256 local parent, name = dir_base(path)\
1257 fileder.facets['name: alpha'] = name\
1258 table.insert(fileders[parent].children, fileder)\
1259 for fn, ft in store:list_facets(path) do\
1260 local val = store:load_facet(path, fn, ft)\
1261 fileder.facets[Key(fn, ft)] = val\
1262 end\
1263 end\
1264 return root\
1265 end\
1266 return {\
1267 Key = Key,\
1268 Fileder = Fileder,\
1269 dir_base = dir_base,\
1270 load_tree = load_tree\
1271 }\
1272 ", "mmm/mmmfs/fileder.lua") end
1273 if not p["mmm.mmmfs"] then p["mmm.mmmfs"] = load("local require = relative(...)\
1274 local Key, Fileder\
1275 do\
1276 local _obj_0 = require('.fileder')\
1277 Key, Fileder = _obj_0.Key, _obj_0.Fileder\
1278 end\
1279 local Browser\
1280 Browser = require('.browser').Browser\
1281 return {\
1282 Key = Key,\
1283 Fileder = Fileder,\
1284 Browser = Browser\
1285 }\
1286 ", "mmm/mmmfs/init.lua") end
1287 if not p["mmm.mmmfs.util"] then p["mmm.mmmfs.util"] = load("local merge\
1288 merge = function(orig, extra)\
1289 if orig == nil then\
1290 orig = { }\
1291 end\
1292 do\
1293 local attr\
1294 do\
1295 local _tbl_0 = { }\
1296 for k, v in pairs(orig) do\
1297 _tbl_0[k] = v\
1298 end\
1299 attr = _tbl_0\
1300 end\
1301 for k, v in pairs(extra) do\
1302 attr[k] = v\
1303 end\
1304 return attr\
1305 end\
1306 end\
1307 local tourl\
1308 tourl = function(path)\
1309 if STATIC then\
1310 return path .. '/'\
1311 else\
1312 return path .. '/'\
1313 end\
1314 end\
1315 return function(elements)\
1316 local a, div, pre\
1317 a, div, pre = elements.a, elements.div, elements.pre\
1318 local find_fileder\
1319 find_fileder = function(fileder, origin)\
1320 if 'string' == type(fileder) then\
1321 assert(origin, \"cannot resolve path '\" .. tostring(fileder) .. \"' without origin!\")\
1322 return assert((origin:walk(fileder)), \"couldn't resolve path '\" .. tostring(fileder) .. \"' from \" .. tostring(origin))\
1323 else\
1324 return assert(fileder, \"no fileder passed.\")\
1325 end\
1326 end\
1327 local navigate_to\
1328 navigate_to = function(path, name, opts)\
1329 if opts == nil then\
1330 opts = { }\
1331 end\
1332 opts.href = tourl(path)\
1333 if MODE == 'CLIENT' then\
1334 opts.onclick = function(self, e)\
1335 e:preventDefault()\
1336 return BROWSER:navigate(path)\
1337 end\
1338 end\
1339 return a(name, opts)\
1340 end\
1341 local link_to\
1342 link_to = function(fileder, name, origin, attr)\
1343 fileder = find_fileder(fileder, origin)\
1344 name = name or fileder:get('title: mmm/dom')\
1345 name = name or fileder:gett('name: alpha')\
1346 do\
1347 local href = fileder:get('link: URL.*')\
1348 if href then\
1349 return a(name, merge(attr, {\
1350 href = href,\
1351 target = '_blank'\
1352 }))\
1353 else\
1354 return a(name, merge(attr, {\
1355 href = tourl(fileder.path),\
1356 onclick = (function()\
1357 if MODE == 'CLIENT' then\
1358 return function(self, e)\
1359 e:preventDefault()\
1360 return BROWSER:navigate(fileder.path)\
1361 end\
1362 end\
1363 end)()\
1364 }))\
1365 end\
1366 end\
1367 end\
1368 local embed\
1369 embed = function(fileder, name, origin, opts)\
1370 if name == nil then\
1371 name = ''\
1372 end\
1373 if opts == nil then\
1374 opts = { }\
1375 end\
1376 fileder = find_fileder(fileder, origin)\
1377 local ok, node = pcall(fileder.gett, fileder, name, 'mmm/dom')\
1378 if not ok then\
1379 return div(\"couldn't embed \" .. tostring(fileder) .. \" \" .. tostring(name), (pre(node)), {\
1380 style = {\
1381 background = 'var(--gray-fail)',\
1382 padding = '1em'\
1383 }\
1384 })\
1385 end\
1386 local klass = 'embed'\
1387 if opts.desc then\
1388 klass = klass .. ' desc'\
1389 end\
1390 if opts.inline then\
1391 klass = klass .. ' inline'\
1392 end\
1393 node = div({\
1394 class = klass,\
1395 node,\
1396 (function()\
1397 if opts.desc then\
1398 return div(opts.desc, {\
1399 class = 'description'\
1400 })\
1401 end\
1402 end)()\
1403 })\
1404 if opts.nolink then\
1405 return node\
1406 end\
1407 return link_to(fileder, node, nil, opts.attr)\
1408 end\
1409 return {\
1410 find_fileder = find_fileder,\
1411 link_to = link_to,\
1412 navigate_to = navigate_to,\
1413 embed = embed\
1414 }\
1415 end\
1416 ", "mmm/mmmfs/util.lua") end
1417 if not p["mmm.mmmfs.converts"] then p["mmm.mmmfs.converts"] = load("local require = relative(..., 1)\
1418 local div, code, img, video, blockquote, a, span, source, iframe\
1419 do\
1420 local _obj_0 = require('mmm.dom')\
1421 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\
1422 end\
1423 local find_fileder, link_to, embed\
1424 do\
1425 local _obj_0 = (require('mmm.mmmfs.util'))(require('mmm.dom'))\
1426 find_fileder, link_to, embed = _obj_0.find_fileder, _obj_0.link_to, _obj_0.embed\
1427 end\
1428 local render\
1429 render = require('.layout').render\
1430 local tohtml\
1431 tohtml = require('mmm.component').tohtml\
1432 local js_fix\
1433 if MODE == 'CLIENT' then\
1434 js_fix = function(arg)\
1435 if arg == js.null then\
1436 return \
1437 end\
1438 return arg\
1439 end\
1440 end\
1441 local single\
1442 single = function(func)\
1443 return function(self, val)\
1444 return func(val)\
1445 end\
1446 end\
1447 local loadwith\
1448 loadwith = function(_load)\
1449 return function(self, val, fileder, key)\
1450 local func = assert(_load(val, tostring(fileder) .. \"#\" .. tostring(key)))\
1451 return func()\
1452 end\
1453 end\
1454 local converts = {\
1455 {\
1456 inp = 'fn -> (.+)',\
1457 out = '%1',\
1458 transform = function(self, val, fileder)\
1459 return val(fileder)\
1460 end\
1461 },\
1462 {\
1463 inp = 'mmm/component',\
1464 out = 'mmm/dom',\
1465 transform = single(tohtml)\
1466 },\
1467 {\
1468 inp = 'mmm/dom',\
1469 out = 'text/html+frag',\
1470 transform = function(self, node)\
1471 if MODE == 'SERVER' then\
1472 return node\
1473 else\
1474 return node.outerHTML\
1475 end\
1476 end\
1477 },\
1478 {\
1479 inp = 'mmm/dom',\
1480 out = 'text/html',\
1481 transform = function(self, html, fileder)\
1482 return render(html, fileder)\
1483 end\
1484 },\
1485 {\
1486 inp = 'text/html%+frag',\
1487 out = 'mmm/dom',\
1488 transform = (function()\
1489 if MODE == 'SERVER' then\
1490 return function(self, html, fileder)\
1491 html = html:gsub('<mmm%-link%s+(.-)>(.-)</mmm%-link>', function(attrs, text)\
1492 if #text == 0 then\
1493 text = nil\
1494 end\
1495 local path = ''\
1496 while attrs and attrs ~= '' do\
1497 local key, val, _attrs = attrs:match('^(%w+)=\"([^\"]-)\"%s*(.*)')\
1498 if not key then\
1499 key, _attrs = attrs:match('^(%w+)%s*(.*)$')\
1500 val = true\
1501 end\
1502 attrs = _attrs\
1503 local _exp_0 = key\
1504 if 'path' == _exp_0 then\
1505 path = val\
1506 else\
1507 warn(\"unkown attribute '\" .. tostring(key) .. \"=\\\"\" .. tostring(val) .. \"\\\"' in <mmm-link>\")\
1508 end\
1509 end\
1510 return link_to(path, text, fileder)\
1511 end)\
1512 html = html:gsub('<mmm%-embed%s+(.-)>(.-)</mmm%-embed>', function(attrs, desc)\
1513 local path, facet = '', ''\
1514 local opts = { }\
1515 if #desc ~= 0 then\
1516 opts.desc = desc\
1517 end\
1518 while attrs and attrs ~= '' do\
1519 local key, val, _attrs = attrs:match('^(%w+)=\"([^\"]-)\"%s*(.*)')\
1520 if not key then\
1521 key, _attrs = attrs:match('^(%w+)%s*(.*)$')\
1522 val = true\
1523 end\
1524 attrs = _attrs\
1525 local _exp_0 = key\
1526 if 'path' == _exp_0 then\
1527 path = val\
1528 elseif 'facet' == _exp_0 then\
1529 facet = val\
1530 elseif 'nolink' == _exp_0 then\
1531 opts.nolink = true\
1532 elseif 'inline' == _exp_0 then\
1533 opts.inline = true\
1534 else\
1535 warn(\"unkown attribute '\" .. tostring(key) .. \"=\\\"\" .. tostring(val) .. \"\\\"' in <mmm-embed>\")\
1536 end\
1537 end\
1538 return embed(path, facet, fileder, opts)\
1539 end)\
1540 return html\
1541 end\
1542 else\
1543 return function(self, html, fileder)\
1544 local parent\
1545 do\
1546 local _with_0 = document:createElement('div')\
1547 _with_0.innerHTML = html\
1548 local embeds = _with_0:getElementsByTagName('mmm-embed')\
1549 do\
1550 local _accum_0 = { }\
1551 local _len_0 = 1\
1552 for i = 0, embeds.length - 1 do\
1553 _accum_0[_len_0] = embeds[i]\
1554 _len_0 = _len_0 + 1\
1555 end\
1556 embeds = _accum_0\
1557 end\
1558 for _index_0 = 1, #embeds do\
1559 local element = embeds[_index_0]\
1560 local path = js_fix(element:getAttribute('path'))\
1561 local facet = js_fix(element:getAttribute('facet'))\
1562 local nolink = js_fix(element:getAttribute('nolink'))\
1563 local inline = js_fix(element:getAttribute('inline'))\
1564 local desc = js_fix(element.innerText)\
1565 element:replaceWith(embed(path or '', facet or '', fileder, {\
1566 nolink = nolink,\
1567 inline = inline,\
1568 desc = desc\
1569 }))\
1570 end\
1571 embeds = _with_0:getElementsByTagName('mmm-link')\
1572 do\
1573 local _accum_0 = { }\
1574 local _len_0 = 1\
1575 for i = 0, embeds.length - 1 do\
1576 _accum_0[_len_0] = embeds[i]\
1577 _len_0 = _len_0 + 1\
1578 end\
1579 embeds = _accum_0\
1580 end\
1581 for _index_0 = 1, #embeds do\
1582 local element = embeds[_index_0]\
1583 local text = js_fix(element.innerText)\
1584 local path = js_fix(element:getAttribute('path'))\
1585 element:replaceWith(link_to(path or '', text, fileder))\
1586 end\
1587 parent = _with_0\
1588 end\
1589 assert(1 == parent.childElementCount, \"text/html with more than one child!\")\
1590 return parent.firstElementChild\
1591 end\
1592 end\
1593 end)()\
1594 },\
1595 {\
1596 inp = 'text/lua -> (.+)',\
1597 out = '%1',\
1598 transform = loadwith(load or loadstring)\
1599 },\
1600 {\
1601 inp = 'mmm/tpl -> (.+)',\
1602 out = '%1',\
1603 transform = function(self, source, fileder)\
1604 return source:gsub('{{(.-)}}', function(expr)\
1605 local path, facet = expr:match('^([%w%-_%./]*)%+(.*)')\
1606 assert(path, \"couldn't match TPL expression '\" .. tostring(expr) .. \"'\")\
1607 return (find_fileder(path, fileder)):gett(facet)\
1608 end)\
1609 end\
1610 },\
1611 {\
1612 inp = 'time/iso8601-date',\
1613 out = 'time/unix',\
1614 transform = function(self, val)\
1615 local year, _, month, day = val:match('^%s*(%d%d%d%d)(%-?)([01]%d)%2([0-3]%d)%s*$')\
1616 assert(year, \"failed to parse ISO 8601 date: '\" .. tostring(val) .. \"'\")\
1617 return os.time({\
1618 year = year,\
1619 month = month,\
1620 day = day\
1621 })\
1622 end\
1623 },\
1624 {\
1625 inp = 'URL -> twitter/tweet',\
1626 out = 'mmm/dom',\
1627 transform = function(self, href)\
1628 local id = assert((href:match('twitter.com/[^/]-/status/(%d*)')), \"couldn't parse twitter/tweet URL: '\" .. tostring(href) .. \"'\")\
1629 if MODE == 'CLIENT' then\
1630 do\
1631 local parent = div()\
1632 window.twttr.widgets:createTweet(id, parent)\
1633 return parent\
1634 end\
1635 else\
1636 return div(blockquote({\
1637 class = 'twitter-tweet',\
1638 ['data-lang'] = 'en',\
1639 a('(linked tweet)', {\
1640 href = href\
1641 })\
1642 }))\
1643 end\
1644 end\
1645 },\
1646 {\
1647 inp = 'URL -> youtube/video',\
1648 out = 'mmm/dom',\
1649 transform = function(self, link)\
1650 local id = link:match('youtu%.be/([^/]+)')\
1651 id = id or link:match('youtube.com/watch.*[?&]v=([^&]+)')\
1652 id = id or link:match('youtube.com/[ev]/([^/]+)')\
1653 id = id or link:match('youtube.com/embed/([^/]+)')\
1654 assert(id, \"couldn't parse youtube URL: '\" .. tostring(link) .. \"'\")\
1655 return iframe({\
1656 width = 560,\
1657 height = 315,\
1658 frameborder = 0,\
1659 allowfullscreen = true,\
1660 frameBorder = 0,\
1661 src = \"//www.youtube.com/embed/\" .. tostring(id)\
1662 })\
1663 end\
1664 },\
1665 {\
1666 inp = 'URL -> image/.+',\
1667 out = 'mmm/dom',\
1668 transform = function(self, src, fileder)\
1669 return img({\
1670 src = src\
1671 })\
1672 end\
1673 },\
1674 {\
1675 inp = 'URL -> video/.+',\
1676 out = 'mmm/dom',\
1677 transform = function(self, src)\
1678 return video((source({\
1679 src = src\
1680 })), {\
1681 controls = true,\
1682 loop = true\
1683 })\
1684 end\
1685 },\
1686 {\
1687 inp = 'text/plain',\
1688 out = 'mmm/dom',\
1689 transform = function(self, val)\
1690 return span(val)\
1691 end\
1692 },\
1693 {\
1694 inp = 'alpha',\
1695 out = 'mmm/dom',\
1696 transform = single(code)\
1697 },\
1698 {\
1699 inp = '(.+)',\
1700 out = 'URL -> %1',\
1701 transform = function(self, _, fileder, key)\
1702 return tostring(fileder.path) .. \"/\" .. tostring(key.name) .. \":\" .. tostring(self.from)\
1703 end\
1704 }\
1705 }\
1706 if MODE == 'SERVER' then\
1707 local ok, moon = pcall(require, 'moonscript.base')\
1708 if ok then\
1709 local _load = moon.load or moon.loadstring\
1710 table.insert(converts, {\
1711 inp = 'text/moonscript -> (.+)',\
1712 out = '%1',\
1713 transform = loadwith(moon.load or moon.loadstring)\
1714 })\
1715 table.insert(converts, {\
1716 inp = 'text/moonscript -> (.+)',\
1717 out = 'text/lua -> %1',\
1718 transform = single(moon.to_lua)\
1719 })\
1720 end\
1721 else\
1722 table.insert(converts, {\
1723 inp = 'text/javascript -> (.+)',\
1724 out = '%1',\
1725 transform = function(self, source)\
1726 local f = js.new(window.Function, source)\
1727 return f()\
1728 end\
1729 })\
1730 end\
1731 do\
1732 local markdown\
1733 if MODE == 'SERVER' then\
1734 local success, discount = pcall(require, 'discount')\
1735 if not success then\
1736 warn(\"NO MARKDOWN SUPPORT!\", discount)\
1737 end\
1738 markdown = success and function(md)\
1739 local res = assert(discount.compile(md, 'githubtags'))\
1740 return res.body\
1741 end\
1742 else\
1743 markdown = window and window.marked and (function()\
1744 local _base_0 = window\
1745 local _fn_0 = _base_0.marked\
1746 return function(...)\
1747 return _fn_0(_base_0, ...)\
1748 end\
1749 end)()\
1750 end\
1751 if markdown then\
1752 table.insert(converts, {\
1753 inp = 'text/markdown',\
1754 out = 'text/html+frag',\
1755 transform = function(self, md)\
1756 return \"<div class=\\\"markdown\\\">\" .. tostring(markdown(md)) .. \"</div>\"\
1757 end\
1758 })\
1759 table.insert(converts, {\
1760 inp = 'text/markdown%+span',\
1761 out = 'mmm/dom',\
1762 transform = (function()\
1763 if MODE == 'SERVER' then\
1764 return function(self, source)\
1765 local html = markdown(source)\
1766 html = html:gsub('^<p', '<span')\
1767 return html:gsub('/p>$', '/span>')\
1768 end\
1769 else\
1770 return function(self, source)\
1771 local html = markdown(source)\
1772 html = html:gsub('^%s*<p>%s*', '')\
1773 html = html:gsub('%s*</p>%s*$', '')\
1774 do\
1775 local _with_0 = document:createElement('span')\
1776 _with_0.innerHTML = html\
1777 return _with_0\
1778 end\
1779 end\
1780 end\
1781 end)()\
1782 })\
1783 end\