commit 3714d6e1fc9c97d80bb91ab23f995044926af906 Author: Christian Lawson-Perfect Date: Sun Feb 9 20:11:49 2025 +0000 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5694dde --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.make.* +elm-stuff/ +error.txt \ No newline at end of file diff --git a/.watchmakerc b/.watchmakerc new file mode 100644 index 0000000..285f521 --- /dev/null +++ b/.watchmakerc @@ -0,0 +1,2 @@ +extensions: + - .elm \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..092ea03 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +DIRNAME=$(notdir $(CURDIR)) + +ELMS=$(wildcard src/*.elm) + +app.js: src/App.elm $(ELMS) + -elm make $< --output=$@ 2> error.txt + @cat error.txt + +upload: app.js index.html style.css + rsync -avz . clpland:~/domains/somethingorotherwhatever.com/html/$(DIRNAME) + @echo "Uploaded to https://somethingorotherwhatever.com/$(DIRNAME)" \ No newline at end of file diff --git a/app.js b/app.js new file mode 100644 index 0000000..4813237 --- /dev/null +++ b/app.js @@ -0,0 +1,9302 @@ +(function(scope){ +'use strict'; + +function F(arity, fun, wrapper) { + wrapper.a = arity; + wrapper.f = fun; + return wrapper; +} + +function F2(fun) { + return F(2, fun, function(a) { return function(b) { return fun(a,b); }; }) +} +function F3(fun) { + return F(3, fun, function(a) { + return function(b) { return function(c) { return fun(a, b, c); }; }; + }); +} +function F4(fun) { + return F(4, fun, function(a) { return function(b) { return function(c) { + return function(d) { return fun(a, b, c, d); }; }; }; + }); +} +function F5(fun) { + return F(5, fun, function(a) { return function(b) { return function(c) { + return function(d) { return function(e) { return fun(a, b, c, d, e); }; }; }; }; + }); +} +function F6(fun) { + return F(6, fun, function(a) { return function(b) { return function(c) { + return function(d) { return function(e) { return function(f) { + return fun(a, b, c, d, e, f); }; }; }; }; }; + }); +} +function F7(fun) { + return F(7, fun, function(a) { return function(b) { return function(c) { + return function(d) { return function(e) { return function(f) { + return function(g) { return fun(a, b, c, d, e, f, g); }; }; }; }; }; }; + }); +} +function F8(fun) { + return F(8, fun, function(a) { return function(b) { return function(c) { + return function(d) { return function(e) { return function(f) { + return function(g) { return function(h) { + return fun(a, b, c, d, e, f, g, h); }; }; }; }; }; }; }; + }); +} +function F9(fun) { + return F(9, fun, function(a) { return function(b) { return function(c) { + return function(d) { return function(e) { return function(f) { + return function(g) { return function(h) { return function(i) { + return fun(a, b, c, d, e, f, g, h, i); }; }; }; }; }; }; }; }; + }); +} + +function A2(fun, a, b) { + return fun.a === 2 ? fun.f(a, b) : fun(a)(b); +} +function A3(fun, a, b, c) { + return fun.a === 3 ? fun.f(a, b, c) : fun(a)(b)(c); +} +function A4(fun, a, b, c, d) { + return fun.a === 4 ? fun.f(a, b, c, d) : fun(a)(b)(c)(d); +} +function A5(fun, a, b, c, d, e) { + return fun.a === 5 ? fun.f(a, b, c, d, e) : fun(a)(b)(c)(d)(e); +} +function A6(fun, a, b, c, d, e, f) { + return fun.a === 6 ? fun.f(a, b, c, d, e, f) : fun(a)(b)(c)(d)(e)(f); +} +function A7(fun, a, b, c, d, e, f, g) { + return fun.a === 7 ? fun.f(a, b, c, d, e, f, g) : fun(a)(b)(c)(d)(e)(f)(g); +} +function A8(fun, a, b, c, d, e, f, g, h) { + return fun.a === 8 ? fun.f(a, b, c, d, e, f, g, h) : fun(a)(b)(c)(d)(e)(f)(g)(h); +} +function A9(fun, a, b, c, d, e, f, g, h, i) { + return fun.a === 9 ? fun.f(a, b, c, d, e, f, g, h, i) : fun(a)(b)(c)(d)(e)(f)(g)(h)(i); +} + +console.warn('Compiled in DEV mode. Follow the advice at https://elm-lang.org/0.19.1/optimize for better performance and smaller assets.'); + + +// EQUALITY + +function _Utils_eq(x, y) +{ + for ( + var pair, stack = [], isEqual = _Utils_eqHelp(x, y, 0, stack); + isEqual && (pair = stack.pop()); + isEqual = _Utils_eqHelp(pair.a, pair.b, 0, stack) + ) + {} + + return isEqual; +} + +function _Utils_eqHelp(x, y, depth, stack) +{ + if (x === y) + { + return true; + } + + if (typeof x !== 'object' || x === null || y === null) + { + typeof x === 'function' && _Debug_crash(5); + return false; + } + + if (depth > 100) + { + stack.push(_Utils_Tuple2(x,y)); + return true; + } + + /**/ + if (x.$ === 'Set_elm_builtin') + { + x = $elm$core$Set$toList(x); + y = $elm$core$Set$toList(y); + } + if (x.$ === 'RBNode_elm_builtin' || x.$ === 'RBEmpty_elm_builtin') + { + x = $elm$core$Dict$toList(x); + y = $elm$core$Dict$toList(y); + } + //*/ + + /**_UNUSED/ + if (x.$ < 0) + { + x = $elm$core$Dict$toList(x); + y = $elm$core$Dict$toList(y); + } + //*/ + + for (var key in x) + { + if (!_Utils_eqHelp(x[key], y[key], depth + 1, stack)) + { + return false; + } + } + return true; +} + +var _Utils_equal = F2(_Utils_eq); +var _Utils_notEqual = F2(function(a, b) { return !_Utils_eq(a,b); }); + + + +// COMPARISONS + +// Code in Generate/JavaScript.hs, Basics.js, and List.js depends on +// the particular integer values assigned to LT, EQ, and GT. + +function _Utils_cmp(x, y, ord) +{ + if (typeof x !== 'object') + { + return x === y ? /*EQ*/ 0 : x < y ? /*LT*/ -1 : /*GT*/ 1; + } + + /**/ + if (x instanceof String) + { + var a = x.valueOf(); + var b = y.valueOf(); + return a === b ? 0 : a < b ? -1 : 1; + } + //*/ + + /**_UNUSED/ + if (typeof x.$ === 'undefined') + //*/ + /**/ + if (x.$[0] === '#') + //*/ + { + return (ord = _Utils_cmp(x.a, y.a)) + ? ord + : (ord = _Utils_cmp(x.b, y.b)) + ? ord + : _Utils_cmp(x.c, y.c); + } + + // traverse conses until end of a list or a mismatch + for (; x.b && y.b && !(ord = _Utils_cmp(x.a, y.a)); x = x.b, y = y.b) {} // WHILE_CONSES + return ord || (x.b ? /*GT*/ 1 : y.b ? /*LT*/ -1 : /*EQ*/ 0); +} + +var _Utils_lt = F2(function(a, b) { return _Utils_cmp(a, b) < 0; }); +var _Utils_le = F2(function(a, b) { return _Utils_cmp(a, b) < 1; }); +var _Utils_gt = F2(function(a, b) { return _Utils_cmp(a, b) > 0; }); +var _Utils_ge = F2(function(a, b) { return _Utils_cmp(a, b) >= 0; }); + +var _Utils_compare = F2(function(x, y) +{ + var n = _Utils_cmp(x, y); + return n < 0 ? $elm$core$Basics$LT : n ? $elm$core$Basics$GT : $elm$core$Basics$EQ; +}); + + +// COMMON VALUES + +var _Utils_Tuple0_UNUSED = 0; +var _Utils_Tuple0 = { $: '#0' }; + +function _Utils_Tuple2_UNUSED(a, b) { return { a: a, b: b }; } +function _Utils_Tuple2(a, b) { return { $: '#2', a: a, b: b }; } + +function _Utils_Tuple3_UNUSED(a, b, c) { return { a: a, b: b, c: c }; } +function _Utils_Tuple3(a, b, c) { return { $: '#3', a: a, b: b, c: c }; } + +function _Utils_chr_UNUSED(c) { return c; } +function _Utils_chr(c) { return new String(c); } + + +// RECORDS + +function _Utils_update(oldRecord, updatedFields) +{ + var newRecord = {}; + + for (var key in oldRecord) + { + newRecord[key] = oldRecord[key]; + } + + for (var key in updatedFields) + { + newRecord[key] = updatedFields[key]; + } + + return newRecord; +} + + +// APPEND + +var _Utils_append = F2(_Utils_ap); + +function _Utils_ap(xs, ys) +{ + // append Strings + if (typeof xs === 'string') + { + return xs + ys; + } + + // append Lists + if (!xs.b) + { + return ys; + } + var root = _List_Cons(xs.a, ys); + xs = xs.b + for (var curr = root; xs.b; xs = xs.b) // WHILE_CONS + { + curr = curr.b = _List_Cons(xs.a, ys); + } + return root; +} + + + +var _List_Nil_UNUSED = { $: 0 }; +var _List_Nil = { $: '[]' }; + +function _List_Cons_UNUSED(hd, tl) { return { $: 1, a: hd, b: tl }; } +function _List_Cons(hd, tl) { return { $: '::', a: hd, b: tl }; } + + +var _List_cons = F2(_List_Cons); + +function _List_fromArray(arr) +{ + var out = _List_Nil; + for (var i = arr.length; i--; ) + { + out = _List_Cons(arr[i], out); + } + return out; +} + +function _List_toArray(xs) +{ + for (var out = []; xs.b; xs = xs.b) // WHILE_CONS + { + out.push(xs.a); + } + return out; +} + +var _List_map2 = F3(function(f, xs, ys) +{ + for (var arr = []; xs.b && ys.b; xs = xs.b, ys = ys.b) // WHILE_CONSES + { + arr.push(A2(f, xs.a, ys.a)); + } + return _List_fromArray(arr); +}); + +var _List_map3 = F4(function(f, xs, ys, zs) +{ + for (var arr = []; xs.b && ys.b && zs.b; xs = xs.b, ys = ys.b, zs = zs.b) // WHILE_CONSES + { + arr.push(A3(f, xs.a, ys.a, zs.a)); + } + return _List_fromArray(arr); +}); + +var _List_map4 = F5(function(f, ws, xs, ys, zs) +{ + for (var arr = []; ws.b && xs.b && ys.b && zs.b; ws = ws.b, xs = xs.b, ys = ys.b, zs = zs.b) // WHILE_CONSES + { + arr.push(A4(f, ws.a, xs.a, ys.a, zs.a)); + } + return _List_fromArray(arr); +}); + +var _List_map5 = F6(function(f, vs, ws, xs, ys, zs) +{ + for (var arr = []; vs.b && ws.b && xs.b && ys.b && zs.b; vs = vs.b, ws = ws.b, xs = xs.b, ys = ys.b, zs = zs.b) // WHILE_CONSES + { + arr.push(A5(f, vs.a, ws.a, xs.a, ys.a, zs.a)); + } + return _List_fromArray(arr); +}); + +var _List_sortBy = F2(function(f, xs) +{ + return _List_fromArray(_List_toArray(xs).sort(function(a, b) { + return _Utils_cmp(f(a), f(b)); + })); +}); + +var _List_sortWith = F2(function(f, xs) +{ + return _List_fromArray(_List_toArray(xs).sort(function(a, b) { + var ord = A2(f, a, b); + return ord === $elm$core$Basics$EQ ? 0 : ord === $elm$core$Basics$LT ? -1 : 1; + })); +}); + + + +var _JsArray_empty = []; + +function _JsArray_singleton(value) +{ + return [value]; +} + +function _JsArray_length(array) +{ + return array.length; +} + +var _JsArray_initialize = F3(function(size, offset, func) +{ + var result = new Array(size); + + for (var i = 0; i < size; i++) + { + result[i] = func(offset + i); + } + + return result; +}); + +var _JsArray_initializeFromList = F2(function (max, ls) +{ + var result = new Array(max); + + for (var i = 0; i < max && ls.b; i++) + { + result[i] = ls.a; + ls = ls.b; + } + + result.length = i; + return _Utils_Tuple2(result, ls); +}); + +var _JsArray_unsafeGet = F2(function(index, array) +{ + return array[index]; +}); + +var _JsArray_unsafeSet = F3(function(index, value, array) +{ + var length = array.length; + var result = new Array(length); + + for (var i = 0; i < length; i++) + { + result[i] = array[i]; + } + + result[index] = value; + return result; +}); + +var _JsArray_push = F2(function(value, array) +{ + var length = array.length; + var result = new Array(length + 1); + + for (var i = 0; i < length; i++) + { + result[i] = array[i]; + } + + result[length] = value; + return result; +}); + +var _JsArray_foldl = F3(function(func, acc, array) +{ + var length = array.length; + + for (var i = 0; i < length; i++) + { + acc = A2(func, array[i], acc); + } + + return acc; +}); + +var _JsArray_foldr = F3(function(func, acc, array) +{ + for (var i = array.length - 1; i >= 0; i--) + { + acc = A2(func, array[i], acc); + } + + return acc; +}); + +var _JsArray_map = F2(function(func, array) +{ + var length = array.length; + var result = new Array(length); + + for (var i = 0; i < length; i++) + { + result[i] = func(array[i]); + } + + return result; +}); + +var _JsArray_indexedMap = F3(function(func, offset, array) +{ + var length = array.length; + var result = new Array(length); + + for (var i = 0; i < length; i++) + { + result[i] = A2(func, offset + i, array[i]); + } + + return result; +}); + +var _JsArray_slice = F3(function(from, to, array) +{ + return array.slice(from, to); +}); + +var _JsArray_appendN = F3(function(n, dest, source) +{ + var destLen = dest.length; + var itemsToCopy = n - destLen; + + if (itemsToCopy > source.length) + { + itemsToCopy = source.length; + } + + var size = destLen + itemsToCopy; + var result = new Array(size); + + for (var i = 0; i < destLen; i++) + { + result[i] = dest[i]; + } + + for (var i = 0; i < itemsToCopy; i++) + { + result[i + destLen] = source[i]; + } + + return result; +}); + + + +// LOG + +var _Debug_log_UNUSED = F2(function(tag, value) +{ + return value; +}); + +var _Debug_log = F2(function(tag, value) +{ + console.log(tag + ': ' + _Debug_toString(value)); + return value; +}); + + +// TODOS + +function _Debug_todo(moduleName, region) +{ + return function(message) { + _Debug_crash(8, moduleName, region, message); + }; +} + +function _Debug_todoCase(moduleName, region, value) +{ + return function(message) { + _Debug_crash(9, moduleName, region, value, message); + }; +} + + +// TO STRING + +function _Debug_toString_UNUSED(value) +{ + return ''; +} + +function _Debug_toString(value) +{ + return _Debug_toAnsiString(false, value); +} + +function _Debug_toAnsiString(ansi, value) +{ + if (typeof value === 'function') + { + return _Debug_internalColor(ansi, ''); + } + + if (typeof value === 'boolean') + { + return _Debug_ctorColor(ansi, value ? 'True' : 'False'); + } + + if (typeof value === 'number') + { + return _Debug_numberColor(ansi, value + ''); + } + + if (value instanceof String) + { + return _Debug_charColor(ansi, "'" + _Debug_addSlashes(value, true) + "'"); + } + + if (typeof value === 'string') + { + return _Debug_stringColor(ansi, '"' + _Debug_addSlashes(value, false) + '"'); + } + + if (typeof value === 'object' && '$' in value) + { + var tag = value.$; + + if (typeof tag === 'number') + { + return _Debug_internalColor(ansi, ''); + } + + if (tag[0] === '#') + { + var output = []; + for (var k in value) + { + if (k === '$') continue; + output.push(_Debug_toAnsiString(ansi, value[k])); + } + return '(' + output.join(',') + ')'; + } + + if (tag === 'Set_elm_builtin') + { + return _Debug_ctorColor(ansi, 'Set') + + _Debug_fadeColor(ansi, '.fromList') + ' ' + + _Debug_toAnsiString(ansi, $elm$core$Set$toList(value)); + } + + if (tag === 'RBNode_elm_builtin' || tag === 'RBEmpty_elm_builtin') + { + return _Debug_ctorColor(ansi, 'Dict') + + _Debug_fadeColor(ansi, '.fromList') + ' ' + + _Debug_toAnsiString(ansi, $elm$core$Dict$toList(value)); + } + + if (tag === 'Array_elm_builtin') + { + return _Debug_ctorColor(ansi, 'Array') + + _Debug_fadeColor(ansi, '.fromList') + ' ' + + _Debug_toAnsiString(ansi, $elm$core$Array$toList(value)); + } + + if (tag === '::' || tag === '[]') + { + var output = '['; + + value.b && (output += _Debug_toAnsiString(ansi, value.a), value = value.b) + + for (; value.b; value = value.b) // WHILE_CONS + { + output += ',' + _Debug_toAnsiString(ansi, value.a); + } + return output + ']'; + } + + var output = ''; + for (var i in value) + { + if (i === '$') continue; + var str = _Debug_toAnsiString(ansi, value[i]); + var c0 = str[0]; + var parenless = c0 === '{' || c0 === '(' || c0 === '[' || c0 === '<' || c0 === '"' || str.indexOf(' ') < 0; + output += ' ' + (parenless ? str : '(' + str + ')'); + } + return _Debug_ctorColor(ansi, tag) + output; + } + + if (typeof DataView === 'function' && value instanceof DataView) + { + return _Debug_stringColor(ansi, '<' + value.byteLength + ' bytes>'); + } + + if (typeof File !== 'undefined' && value instanceof File) + { + return _Debug_internalColor(ansi, '<' + value.name + '>'); + } + + if (typeof value === 'object') + { + var output = []; + for (var key in value) + { + var field = key[0] === '_' ? key.slice(1) : key; + output.push(_Debug_fadeColor(ansi, field) + ' = ' + _Debug_toAnsiString(ansi, value[key])); + } + if (output.length === 0) + { + return '{}'; + } + return '{ ' + output.join(', ') + ' }'; + } + + return _Debug_internalColor(ansi, ''); +} + +function _Debug_addSlashes(str, isChar) +{ + var s = str + .replace(/\\/g, '\\\\') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + .replace(/\r/g, '\\r') + .replace(/\v/g, '\\v') + .replace(/\0/g, '\\0'); + + if (isChar) + { + return s.replace(/\'/g, '\\\''); + } + else + { + return s.replace(/\"/g, '\\"'); + } +} + +function _Debug_ctorColor(ansi, string) +{ + return ansi ? '\x1b[96m' + string + '\x1b[0m' : string; +} + +function _Debug_numberColor(ansi, string) +{ + return ansi ? '\x1b[95m' + string + '\x1b[0m' : string; +} + +function _Debug_stringColor(ansi, string) +{ + return ansi ? '\x1b[93m' + string + '\x1b[0m' : string; +} + +function _Debug_charColor(ansi, string) +{ + return ansi ? '\x1b[92m' + string + '\x1b[0m' : string; +} + +function _Debug_fadeColor(ansi, string) +{ + return ansi ? '\x1b[37m' + string + '\x1b[0m' : string; +} + +function _Debug_internalColor(ansi, string) +{ + return ansi ? '\x1b[36m' + string + '\x1b[0m' : string; +} + +function _Debug_toHexDigit(n) +{ + return String.fromCharCode(n < 10 ? 48 + n : 55 + n); +} + + +// CRASH + + +function _Debug_crash_UNUSED(identifier) +{ + throw new Error('https://github.com/elm/core/blob/1.0.0/hints/' + identifier + '.md'); +} + + +function _Debug_crash(identifier, fact1, fact2, fact3, fact4) +{ + switch(identifier) + { + case 0: + throw new Error('What node should I take over? In JavaScript I need something like:\n\n Elm.Main.init({\n node: document.getElementById("elm-node")\n })\n\nYou need to do this with any Browser.sandbox or Browser.element program.'); + + case 1: + throw new Error('Browser.application programs cannot handle URLs like this:\n\n ' + document.location.href + '\n\nWhat is the root? The root of your file system? Try looking at this program with `elm reactor` or some other server.'); + + case 2: + var jsonErrorString = fact1; + throw new Error('Problem with the flags given to your Elm program on initialization.\n\n' + jsonErrorString); + + case 3: + var portName = fact1; + throw new Error('There can only be one port named `' + portName + '`, but your program has multiple.'); + + case 4: + var portName = fact1; + var problem = fact2; + throw new Error('Trying to send an unexpected type of value through port `' + portName + '`:\n' + problem); + + case 5: + throw new Error('Trying to use `(==)` on functions.\nThere is no way to know if functions are "the same" in the Elm sense.\nRead more about this at https://package.elm-lang.org/packages/elm/core/latest/Basics#== which describes why it is this way and what the better version will look like.'); + + case 6: + var moduleName = fact1; + throw new Error('Your page is loading multiple Elm scripts with a module named ' + moduleName + '. Maybe a duplicate script is getting loaded accidentally? If not, rename one of them so I know which is which!'); + + case 8: + var moduleName = fact1; + var region = fact2; + var message = fact3; + throw new Error('TODO in module `' + moduleName + '` ' + _Debug_regionToString(region) + '\n\n' + message); + + case 9: + var moduleName = fact1; + var region = fact2; + var value = fact3; + var message = fact4; + throw new Error( + 'TODO in module `' + moduleName + '` from the `case` expression ' + + _Debug_regionToString(region) + '\n\nIt received the following value:\n\n ' + + _Debug_toString(value).replace('\n', '\n ') + + '\n\nBut the branch that handles it says:\n\n ' + message.replace('\n', '\n ') + ); + + case 10: + throw new Error('Bug in https://github.com/elm/virtual-dom/issues'); + + case 11: + throw new Error('Cannot perform mod 0. Division by zero error.'); + } +} + +function _Debug_regionToString(region) +{ + if (region.start.line === region.end.line) + { + return 'on line ' + region.start.line; + } + return 'on lines ' + region.start.line + ' through ' + region.end.line; +} + + + +// MATH + +var _Basics_add = F2(function(a, b) { return a + b; }); +var _Basics_sub = F2(function(a, b) { return a - b; }); +var _Basics_mul = F2(function(a, b) { return a * b; }); +var _Basics_fdiv = F2(function(a, b) { return a / b; }); +var _Basics_idiv = F2(function(a, b) { return (a / b) | 0; }); +var _Basics_pow = F2(Math.pow); + +var _Basics_remainderBy = F2(function(b, a) { return a % b; }); + +// https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf +var _Basics_modBy = F2(function(modulus, x) +{ + var answer = x % modulus; + return modulus === 0 + ? _Debug_crash(11) + : + ((answer > 0 && modulus < 0) || (answer < 0 && modulus > 0)) + ? answer + modulus + : answer; +}); + + +// TRIGONOMETRY + +var _Basics_pi = Math.PI; +var _Basics_e = Math.E; +var _Basics_cos = Math.cos; +var _Basics_sin = Math.sin; +var _Basics_tan = Math.tan; +var _Basics_acos = Math.acos; +var _Basics_asin = Math.asin; +var _Basics_atan = Math.atan; +var _Basics_atan2 = F2(Math.atan2); + + +// MORE MATH + +function _Basics_toFloat(x) { return x; } +function _Basics_truncate(n) { return n | 0; } +function _Basics_isInfinite(n) { return n === Infinity || n === -Infinity; } + +var _Basics_ceiling = Math.ceil; +var _Basics_floor = Math.floor; +var _Basics_round = Math.round; +var _Basics_sqrt = Math.sqrt; +var _Basics_log = Math.log; +var _Basics_isNaN = isNaN; + + +// BOOLEANS + +function _Basics_not(bool) { return !bool; } +var _Basics_and = F2(function(a, b) { return a && b; }); +var _Basics_or = F2(function(a, b) { return a || b; }); +var _Basics_xor = F2(function(a, b) { return a !== b; }); + + + +var _String_cons = F2(function(chr, str) +{ + return chr + str; +}); + +function _String_uncons(string) +{ + var word = string.charCodeAt(0); + return !isNaN(word) + ? $elm$core$Maybe$Just( + 0xD800 <= word && word <= 0xDBFF + ? _Utils_Tuple2(_Utils_chr(string[0] + string[1]), string.slice(2)) + : _Utils_Tuple2(_Utils_chr(string[0]), string.slice(1)) + ) + : $elm$core$Maybe$Nothing; +} + +var _String_append = F2(function(a, b) +{ + return a + b; +}); + +function _String_length(str) +{ + return str.length; +} + +var _String_map = F2(function(func, string) +{ + var len = string.length; + var array = new Array(len); + var i = 0; + while (i < len) + { + var word = string.charCodeAt(i); + if (0xD800 <= word && word <= 0xDBFF) + { + array[i] = func(_Utils_chr(string[i] + string[i+1])); + i += 2; + continue; + } + array[i] = func(_Utils_chr(string[i])); + i++; + } + return array.join(''); +}); + +var _String_filter = F2(function(isGood, str) +{ + var arr = []; + var len = str.length; + var i = 0; + while (i < len) + { + var char = str[i]; + var word = str.charCodeAt(i); + i++; + if (0xD800 <= word && word <= 0xDBFF) + { + char += str[i]; + i++; + } + + if (isGood(_Utils_chr(char))) + { + arr.push(char); + } + } + return arr.join(''); +}); + +function _String_reverse(str) +{ + var len = str.length; + var arr = new Array(len); + var i = 0; + while (i < len) + { + var word = str.charCodeAt(i); + if (0xD800 <= word && word <= 0xDBFF) + { + arr[len - i] = str[i + 1]; + i++; + arr[len - i] = str[i - 1]; + i++; + } + else + { + arr[len - i] = str[i]; + i++; + } + } + return arr.join(''); +} + +var _String_foldl = F3(function(func, state, string) +{ + var len = string.length; + var i = 0; + while (i < len) + { + var char = string[i]; + var word = string.charCodeAt(i); + i++; + if (0xD800 <= word && word <= 0xDBFF) + { + char += string[i]; + i++; + } + state = A2(func, _Utils_chr(char), state); + } + return state; +}); + +var _String_foldr = F3(function(func, state, string) +{ + var i = string.length; + while (i--) + { + var char = string[i]; + var word = string.charCodeAt(i); + if (0xDC00 <= word && word <= 0xDFFF) + { + i--; + char = string[i] + char; + } + state = A2(func, _Utils_chr(char), state); + } + return state; +}); + +var _String_split = F2(function(sep, str) +{ + return str.split(sep); +}); + +var _String_join = F2(function(sep, strs) +{ + return strs.join(sep); +}); + +var _String_slice = F3(function(start, end, str) { + return str.slice(start, end); +}); + +function _String_trim(str) +{ + return str.trim(); +} + +function _String_trimLeft(str) +{ + return str.replace(/^\s+/, ''); +} + +function _String_trimRight(str) +{ + return str.replace(/\s+$/, ''); +} + +function _String_words(str) +{ + return _List_fromArray(str.trim().split(/\s+/g)); +} + +function _String_lines(str) +{ + return _List_fromArray(str.split(/\r\n|\r|\n/g)); +} + +function _String_toUpper(str) +{ + return str.toUpperCase(); +} + +function _String_toLower(str) +{ + return str.toLowerCase(); +} + +var _String_any = F2(function(isGood, string) +{ + var i = string.length; + while (i--) + { + var char = string[i]; + var word = string.charCodeAt(i); + if (0xDC00 <= word && word <= 0xDFFF) + { + i--; + char = string[i] + char; + } + if (isGood(_Utils_chr(char))) + { + return true; + } + } + return false; +}); + +var _String_all = F2(function(isGood, string) +{ + var i = string.length; + while (i--) + { + var char = string[i]; + var word = string.charCodeAt(i); + if (0xDC00 <= word && word <= 0xDFFF) + { + i--; + char = string[i] + char; + } + if (!isGood(_Utils_chr(char))) + { + return false; + } + } + return true; +}); + +var _String_contains = F2(function(sub, str) +{ + return str.indexOf(sub) > -1; +}); + +var _String_startsWith = F2(function(sub, str) +{ + return str.indexOf(sub) === 0; +}); + +var _String_endsWith = F2(function(sub, str) +{ + return str.length >= sub.length && + str.lastIndexOf(sub) === str.length - sub.length; +}); + +var _String_indexes = F2(function(sub, str) +{ + var subLen = sub.length; + + if (subLen < 1) + { + return _List_Nil; + } + + var i = 0; + var is = []; + + while ((i = str.indexOf(sub, i)) > -1) + { + is.push(i); + i = i + subLen; + } + + return _List_fromArray(is); +}); + + +// TO STRING + +function _String_fromNumber(number) +{ + return number + ''; +} + + +// INT CONVERSIONS + +function _String_toInt(str) +{ + var total = 0; + var code0 = str.charCodeAt(0); + var start = code0 == 0x2B /* + */ || code0 == 0x2D /* - */ ? 1 : 0; + + for (var i = start; i < str.length; ++i) + { + var code = str.charCodeAt(i); + if (code < 0x30 || 0x39 < code) + { + return $elm$core$Maybe$Nothing; + } + total = 10 * total + code - 0x30; + } + + return i == start + ? $elm$core$Maybe$Nothing + : $elm$core$Maybe$Just(code0 == 0x2D ? -total : total); +} + + +// FLOAT CONVERSIONS + +function _String_toFloat(s) +{ + // check if it is a hex, octal, or binary number + if (s.length === 0 || /[\sxbo]/.test(s)) + { + return $elm$core$Maybe$Nothing; + } + var n = +s; + // faster isNaN check + return n === n ? $elm$core$Maybe$Just(n) : $elm$core$Maybe$Nothing; +} + +function _String_fromList(chars) +{ + return _List_toArray(chars).join(''); +} + + + + +function _Char_toCode(char) +{ + var code = char.charCodeAt(0); + if (0xD800 <= code && code <= 0xDBFF) + { + return (code - 0xD800) * 0x400 + char.charCodeAt(1) - 0xDC00 + 0x10000 + } + return code; +} + +function _Char_fromCode(code) +{ + return _Utils_chr( + (code < 0 || 0x10FFFF < code) + ? '\uFFFD' + : + (code <= 0xFFFF) + ? String.fromCharCode(code) + : + (code -= 0x10000, + String.fromCharCode(Math.floor(code / 0x400) + 0xD800, code % 0x400 + 0xDC00) + ) + ); +} + +function _Char_toUpper(char) +{ + return _Utils_chr(char.toUpperCase()); +} + +function _Char_toLower(char) +{ + return _Utils_chr(char.toLowerCase()); +} + +function _Char_toLocaleUpper(char) +{ + return _Utils_chr(char.toLocaleUpperCase()); +} + +function _Char_toLocaleLower(char) +{ + return _Utils_chr(char.toLocaleLowerCase()); +} + + + +/**/ +function _Json_errorToString(error) +{ + return $elm$json$Json$Decode$errorToString(error); +} +//*/ + + +// CORE DECODERS + +function _Json_succeed(msg) +{ + return { + $: 0, + a: msg + }; +} + +function _Json_fail(msg) +{ + return { + $: 1, + a: msg + }; +} + +function _Json_decodePrim(decoder) +{ + return { $: 2, b: decoder }; +} + +var _Json_decodeInt = _Json_decodePrim(function(value) { + return (typeof value !== 'number') + ? _Json_expecting('an INT', value) + : + (-2147483647 < value && value < 2147483647 && (value | 0) === value) + ? $elm$core$Result$Ok(value) + : + (isFinite(value) && !(value % 1)) + ? $elm$core$Result$Ok(value) + : _Json_expecting('an INT', value); +}); + +var _Json_decodeBool = _Json_decodePrim(function(value) { + return (typeof value === 'boolean') + ? $elm$core$Result$Ok(value) + : _Json_expecting('a BOOL', value); +}); + +var _Json_decodeFloat = _Json_decodePrim(function(value) { + return (typeof value === 'number') + ? $elm$core$Result$Ok(value) + : _Json_expecting('a FLOAT', value); +}); + +var _Json_decodeValue = _Json_decodePrim(function(value) { + return $elm$core$Result$Ok(_Json_wrap(value)); +}); + +var _Json_decodeString = _Json_decodePrim(function(value) { + return (typeof value === 'string') + ? $elm$core$Result$Ok(value) + : (value instanceof String) + ? $elm$core$Result$Ok(value + '') + : _Json_expecting('a STRING', value); +}); + +function _Json_decodeList(decoder) { return { $: 3, b: decoder }; } +function _Json_decodeArray(decoder) { return { $: 4, b: decoder }; } + +function _Json_decodeNull(value) { return { $: 5, c: value }; } + +var _Json_decodeField = F2(function(field, decoder) +{ + return { + $: 6, + d: field, + b: decoder + }; +}); + +var _Json_decodeIndex = F2(function(index, decoder) +{ + return { + $: 7, + e: index, + b: decoder + }; +}); + +function _Json_decodeKeyValuePairs(decoder) +{ + return { + $: 8, + b: decoder + }; +} + +function _Json_mapMany(f, decoders) +{ + return { + $: 9, + f: f, + g: decoders + }; +} + +var _Json_andThen = F2(function(callback, decoder) +{ + return { + $: 10, + b: decoder, + h: callback + }; +}); + +function _Json_oneOf(decoders) +{ + return { + $: 11, + g: decoders + }; +} + + +// DECODING OBJECTS + +var _Json_map1 = F2(function(f, d1) +{ + return _Json_mapMany(f, [d1]); +}); + +var _Json_map2 = F3(function(f, d1, d2) +{ + return _Json_mapMany(f, [d1, d2]); +}); + +var _Json_map3 = F4(function(f, d1, d2, d3) +{ + return _Json_mapMany(f, [d1, d2, d3]); +}); + +var _Json_map4 = F5(function(f, d1, d2, d3, d4) +{ + return _Json_mapMany(f, [d1, d2, d3, d4]); +}); + +var _Json_map5 = F6(function(f, d1, d2, d3, d4, d5) +{ + return _Json_mapMany(f, [d1, d2, d3, d4, d5]); +}); + +var _Json_map6 = F7(function(f, d1, d2, d3, d4, d5, d6) +{ + return _Json_mapMany(f, [d1, d2, d3, d4, d5, d6]); +}); + +var _Json_map7 = F8(function(f, d1, d2, d3, d4, d5, d6, d7) +{ + return _Json_mapMany(f, [d1, d2, d3, d4, d5, d6, d7]); +}); + +var _Json_map8 = F9(function(f, d1, d2, d3, d4, d5, d6, d7, d8) +{ + return _Json_mapMany(f, [d1, d2, d3, d4, d5, d6, d7, d8]); +}); + + +// DECODE + +var _Json_runOnString = F2(function(decoder, string) +{ + try + { + var value = JSON.parse(string); + return _Json_runHelp(decoder, value); + } + catch (e) + { + return $elm$core$Result$Err(A2($elm$json$Json$Decode$Failure, 'This is not valid JSON! ' + e.message, _Json_wrap(string))); + } +}); + +var _Json_run = F2(function(decoder, value) +{ + return _Json_runHelp(decoder, _Json_unwrap(value)); +}); + +function _Json_runHelp(decoder, value) +{ + switch (decoder.$) + { + case 2: + return decoder.b(value); + + case 5: + return (value === null) + ? $elm$core$Result$Ok(decoder.c) + : _Json_expecting('null', value); + + case 3: + if (!_Json_isArray(value)) + { + return _Json_expecting('a LIST', value); + } + return _Json_runArrayDecoder(decoder.b, value, _List_fromArray); + + case 4: + if (!_Json_isArray(value)) + { + return _Json_expecting('an ARRAY', value); + } + return _Json_runArrayDecoder(decoder.b, value, _Json_toElmArray); + + case 6: + var field = decoder.d; + if (typeof value !== 'object' || value === null || !(field in value)) + { + return _Json_expecting('an OBJECT with a field named `' + field + '`', value); + } + var result = _Json_runHelp(decoder.b, value[field]); + return ($elm$core$Result$isOk(result)) ? result : $elm$core$Result$Err(A2($elm$json$Json$Decode$Field, field, result.a)); + + case 7: + var index = decoder.e; + if (!_Json_isArray(value)) + { + return _Json_expecting('an ARRAY', value); + } + if (index >= value.length) + { + return _Json_expecting('a LONGER array. Need index ' + index + ' but only see ' + value.length + ' entries', value); + } + var result = _Json_runHelp(decoder.b, value[index]); + return ($elm$core$Result$isOk(result)) ? result : $elm$core$Result$Err(A2($elm$json$Json$Decode$Index, index, result.a)); + + case 8: + if (typeof value !== 'object' || value === null || _Json_isArray(value)) + { + return _Json_expecting('an OBJECT', value); + } + + var keyValuePairs = _List_Nil; + // TODO test perf of Object.keys and switch when support is good enough + for (var key in value) + { + if (value.hasOwnProperty(key)) + { + var result = _Json_runHelp(decoder.b, value[key]); + if (!$elm$core$Result$isOk(result)) + { + return $elm$core$Result$Err(A2($elm$json$Json$Decode$Field, key, result.a)); + } + keyValuePairs = _List_Cons(_Utils_Tuple2(key, result.a), keyValuePairs); + } + } + return $elm$core$Result$Ok($elm$core$List$reverse(keyValuePairs)); + + case 9: + var answer = decoder.f; + var decoders = decoder.g; + for (var i = 0; i < decoders.length; i++) + { + var result = _Json_runHelp(decoders[i], value); + if (!$elm$core$Result$isOk(result)) + { + return result; + } + answer = answer(result.a); + } + return $elm$core$Result$Ok(answer); + + case 10: + var result = _Json_runHelp(decoder.b, value); + return (!$elm$core$Result$isOk(result)) + ? result + : _Json_runHelp(decoder.h(result.a), value); + + case 11: + var errors = _List_Nil; + for (var temp = decoder.g; temp.b; temp = temp.b) // WHILE_CONS + { + var result = _Json_runHelp(temp.a, value); + if ($elm$core$Result$isOk(result)) + { + return result; + } + errors = _List_Cons(result.a, errors); + } + return $elm$core$Result$Err($elm$json$Json$Decode$OneOf($elm$core$List$reverse(errors))); + + case 1: + return $elm$core$Result$Err(A2($elm$json$Json$Decode$Failure, decoder.a, _Json_wrap(value))); + + case 0: + return $elm$core$Result$Ok(decoder.a); + } +} + +function _Json_runArrayDecoder(decoder, value, toElmValue) +{ + var len = value.length; + var array = new Array(len); + for (var i = 0; i < len; i++) + { + var result = _Json_runHelp(decoder, value[i]); + if (!$elm$core$Result$isOk(result)) + { + return $elm$core$Result$Err(A2($elm$json$Json$Decode$Index, i, result.a)); + } + array[i] = result.a; + } + return $elm$core$Result$Ok(toElmValue(array)); +} + +function _Json_isArray(value) +{ + return Array.isArray(value) || (typeof FileList !== 'undefined' && value instanceof FileList); +} + +function _Json_toElmArray(array) +{ + return A2($elm$core$Array$initialize, array.length, function(i) { return array[i]; }); +} + +function _Json_expecting(type, value) +{ + return $elm$core$Result$Err(A2($elm$json$Json$Decode$Failure, 'Expecting ' + type, _Json_wrap(value))); +} + + +// EQUALITY + +function _Json_equality(x, y) +{ + if (x === y) + { + return true; + } + + if (x.$ !== y.$) + { + return false; + } + + switch (x.$) + { + case 0: + case 1: + return x.a === y.a; + + case 2: + return x.b === y.b; + + case 5: + return x.c === y.c; + + case 3: + case 4: + case 8: + return _Json_equality(x.b, y.b); + + case 6: + return x.d === y.d && _Json_equality(x.b, y.b); + + case 7: + return x.e === y.e && _Json_equality(x.b, y.b); + + case 9: + return x.f === y.f && _Json_listEquality(x.g, y.g); + + case 10: + return x.h === y.h && _Json_equality(x.b, y.b); + + case 11: + return _Json_listEquality(x.g, y.g); + } +} + +function _Json_listEquality(aDecoders, bDecoders) +{ + var len = aDecoders.length; + if (len !== bDecoders.length) + { + return false; + } + for (var i = 0; i < len; i++) + { + if (!_Json_equality(aDecoders[i], bDecoders[i])) + { + return false; + } + } + return true; +} + + +// ENCODE + +var _Json_encode = F2(function(indentLevel, value) +{ + return JSON.stringify(_Json_unwrap(value), null, indentLevel) + ''; +}); + +function _Json_wrap(value) { return { $: 0, a: value }; } +function _Json_unwrap(value) { return value.a; } + +function _Json_wrap_UNUSED(value) { return value; } +function _Json_unwrap_UNUSED(value) { return value; } + +function _Json_emptyArray() { return []; } +function _Json_emptyObject() { return {}; } + +var _Json_addField = F3(function(key, value, object) +{ + object[key] = _Json_unwrap(value); + return object; +}); + +function _Json_addEntry(func) +{ + return F2(function(entry, array) + { + array.push(_Json_unwrap(func(entry))); + return array; + }); +} + +var _Json_encodeNull = _Json_wrap(null); + + + +// TASKS + +function _Scheduler_succeed(value) +{ + return { + $: 0, + a: value + }; +} + +function _Scheduler_fail(error) +{ + return { + $: 1, + a: error + }; +} + +function _Scheduler_binding(callback) +{ + return { + $: 2, + b: callback, + c: null + }; +} + +var _Scheduler_andThen = F2(function(callback, task) +{ + return { + $: 3, + b: callback, + d: task + }; +}); + +var _Scheduler_onError = F2(function(callback, task) +{ + return { + $: 4, + b: callback, + d: task + }; +}); + +function _Scheduler_receive(callback) +{ + return { + $: 5, + b: callback + }; +} + + +// PROCESSES + +var _Scheduler_guid = 0; + +function _Scheduler_rawSpawn(task) +{ + var proc = { + $: 0, + e: _Scheduler_guid++, + f: task, + g: null, + h: [] + }; + + _Scheduler_enqueue(proc); + + return proc; +} + +function _Scheduler_spawn(task) +{ + return _Scheduler_binding(function(callback) { + callback(_Scheduler_succeed(_Scheduler_rawSpawn(task))); + }); +} + +function _Scheduler_rawSend(proc, msg) +{ + proc.h.push(msg); + _Scheduler_enqueue(proc); +} + +var _Scheduler_send = F2(function(proc, msg) +{ + return _Scheduler_binding(function(callback) { + _Scheduler_rawSend(proc, msg); + callback(_Scheduler_succeed(_Utils_Tuple0)); + }); +}); + +function _Scheduler_kill(proc) +{ + return _Scheduler_binding(function(callback) { + var task = proc.f; + if (task.$ === 2 && task.c) + { + task.c(); + } + + proc.f = null; + + callback(_Scheduler_succeed(_Utils_Tuple0)); + }); +} + + +/* STEP PROCESSES + +type alias Process = + { $ : tag + , id : unique_id + , root : Task + , stack : null | { $: SUCCEED | FAIL, a: callback, b: stack } + , mailbox : [msg] + } + +*/ + + +var _Scheduler_working = false; +var _Scheduler_queue = []; + + +function _Scheduler_enqueue(proc) +{ + _Scheduler_queue.push(proc); + if (_Scheduler_working) + { + return; + } + _Scheduler_working = true; + while (proc = _Scheduler_queue.shift()) + { + _Scheduler_step(proc); + } + _Scheduler_working = false; +} + + +function _Scheduler_step(proc) +{ + while (proc.f) + { + var rootTag = proc.f.$; + if (rootTag === 0 || rootTag === 1) + { + while (proc.g && proc.g.$ !== rootTag) + { + proc.g = proc.g.i; + } + if (!proc.g) + { + return; + } + proc.f = proc.g.b(proc.f.a); + proc.g = proc.g.i; + } + else if (rootTag === 2) + { + proc.f.c = proc.f.b(function(newRoot) { + proc.f = newRoot; + _Scheduler_enqueue(proc); + }); + return; + } + else if (rootTag === 5) + { + if (proc.h.length === 0) + { + return; + } + proc.f = proc.f.b(proc.h.shift()); + } + else // if (rootTag === 3 || rootTag === 4) + { + proc.g = { + $: rootTag === 3 ? 0 : 1, + b: proc.f.b, + i: proc.g + }; + proc.f = proc.f.d; + } + } +} + + + +function _Process_sleep(time) +{ + return _Scheduler_binding(function(callback) { + var id = setTimeout(function() { + callback(_Scheduler_succeed(_Utils_Tuple0)); + }, time); + + return function() { clearTimeout(id); }; + }); +} + + + + +// PROGRAMS + + +var _Platform_worker = F4(function(impl, flagDecoder, debugMetadata, args) +{ + return _Platform_initialize( + flagDecoder, + args, + impl.init, + impl.update, + impl.subscriptions, + function() { return function() {} } + ); +}); + + + +// INITIALIZE A PROGRAM + + +function _Platform_initialize(flagDecoder, args, init, update, subscriptions, stepperBuilder) +{ + var result = A2(_Json_run, flagDecoder, _Json_wrap(args ? args['flags'] : undefined)); + $elm$core$Result$isOk(result) || _Debug_crash(2 /**/, _Json_errorToString(result.a) /**/); + var managers = {}; + var initPair = init(result.a); + var model = initPair.a; + var stepper = stepperBuilder(sendToApp, model); + var ports = _Platform_setupEffects(managers, sendToApp); + + function sendToApp(msg, viewMetadata) + { + var pair = A2(update, msg, model); + stepper(model = pair.a, viewMetadata); + _Platform_enqueueEffects(managers, pair.b, subscriptions(model)); + } + + _Platform_enqueueEffects(managers, initPair.b, subscriptions(model)); + + return ports ? { ports: ports } : {}; +} + + + +// TRACK PRELOADS +// +// This is used by code in elm/browser and elm/http +// to register any HTTP requests that are triggered by init. +// + + +var _Platform_preload; + + +function _Platform_registerPreload(url) +{ + _Platform_preload.add(url); +} + + + +// EFFECT MANAGERS + + +var _Platform_effectManagers = {}; + + +function _Platform_setupEffects(managers, sendToApp) +{ + var ports; + + // setup all necessary effect managers + for (var key in _Platform_effectManagers) + { + var manager = _Platform_effectManagers[key]; + + if (manager.a) + { + ports = ports || {}; + ports[key] = manager.a(key, sendToApp); + } + + managers[key] = _Platform_instantiateManager(manager, sendToApp); + } + + return ports; +} + + +function _Platform_createManager(init, onEffects, onSelfMsg, cmdMap, subMap) +{ + return { + b: init, + c: onEffects, + d: onSelfMsg, + e: cmdMap, + f: subMap + }; +} + + +function _Platform_instantiateManager(info, sendToApp) +{ + var router = { + g: sendToApp, + h: undefined + }; + + var onEffects = info.c; + var onSelfMsg = info.d; + var cmdMap = info.e; + var subMap = info.f; + + function loop(state) + { + return A2(_Scheduler_andThen, loop, _Scheduler_receive(function(msg) + { + var value = msg.a; + + if (msg.$ === 0) + { + return A3(onSelfMsg, router, value, state); + } + + return cmdMap && subMap + ? A4(onEffects, router, value.i, value.j, state) + : A3(onEffects, router, cmdMap ? value.i : value.j, state); + })); + } + + return router.h = _Scheduler_rawSpawn(A2(_Scheduler_andThen, loop, info.b)); +} + + + +// ROUTING + + +var _Platform_sendToApp = F2(function(router, msg) +{ + return _Scheduler_binding(function(callback) + { + router.g(msg); + callback(_Scheduler_succeed(_Utils_Tuple0)); + }); +}); + + +var _Platform_sendToSelf = F2(function(router, msg) +{ + return A2(_Scheduler_send, router.h, { + $: 0, + a: msg + }); +}); + + + +// BAGS + + +function _Platform_leaf(home) +{ + return function(value) + { + return { + $: 1, + k: home, + l: value + }; + }; +} + + +function _Platform_batch(list) +{ + return { + $: 2, + m: list + }; +} + + +var _Platform_map = F2(function(tagger, bag) +{ + return { + $: 3, + n: tagger, + o: bag + } +}); + + + +// PIPE BAGS INTO EFFECT MANAGERS +// +// Effects must be queued! +// +// Say your init contains a synchronous command, like Time.now or Time.here +// +// - This will produce a batch of effects (FX_1) +// - The synchronous task triggers the subsequent `update` call +// - This will produce a batch of effects (FX_2) +// +// If we just start dispatching FX_2, subscriptions from FX_2 can be processed +// before subscriptions from FX_1. No good! Earlier versions of this code had +// this problem, leading to these reports: +// +// https://github.com/elm/core/issues/980 +// https://github.com/elm/core/pull/981 +// https://github.com/elm/compiler/issues/1776 +// +// The queue is necessary to avoid ordering issues for synchronous commands. + + +// Why use true/false here? Why not just check the length of the queue? +// The goal is to detect "are we currently dispatching effects?" If we +// are, we need to bail and let the ongoing while loop handle things. +// +// Now say the queue has 1 element. When we dequeue the final element, +// the queue will be empty, but we are still actively dispatching effects. +// So you could get queue jumping in a really tricky category of cases. +// +var _Platform_effectsQueue = []; +var _Platform_effectsActive = false; + + +function _Platform_enqueueEffects(managers, cmdBag, subBag) +{ + _Platform_effectsQueue.push({ p: managers, q: cmdBag, r: subBag }); + + if (_Platform_effectsActive) return; + + _Platform_effectsActive = true; + for (var fx; fx = _Platform_effectsQueue.shift(); ) + { + _Platform_dispatchEffects(fx.p, fx.q, fx.r); + } + _Platform_effectsActive = false; +} + + +function _Platform_dispatchEffects(managers, cmdBag, subBag) +{ + var effectsDict = {}; + _Platform_gatherEffects(true, cmdBag, effectsDict, null); + _Platform_gatherEffects(false, subBag, effectsDict, null); + + for (var home in managers) + { + _Scheduler_rawSend(managers[home], { + $: 'fx', + a: effectsDict[home] || { i: _List_Nil, j: _List_Nil } + }); + } +} + + +function _Platform_gatherEffects(isCmd, bag, effectsDict, taggers) +{ + switch (bag.$) + { + case 1: + var home = bag.k; + var effect = _Platform_toEffect(isCmd, home, taggers, bag.l); + effectsDict[home] = _Platform_insert(isCmd, effect, effectsDict[home]); + return; + + case 2: + for (var list = bag.m; list.b; list = list.b) // WHILE_CONS + { + _Platform_gatherEffects(isCmd, list.a, effectsDict, taggers); + } + return; + + case 3: + _Platform_gatherEffects(isCmd, bag.o, effectsDict, { + s: bag.n, + t: taggers + }); + return; + } +} + + +function _Platform_toEffect(isCmd, home, taggers, value) +{ + function applyTaggers(x) + { + for (var temp = taggers; temp; temp = temp.t) + { + x = temp.s(x); + } + return x; + } + + var map = isCmd + ? _Platform_effectManagers[home].e + : _Platform_effectManagers[home].f; + + return A2(map, applyTaggers, value) +} + + +function _Platform_insert(isCmd, newEffect, effects) +{ + effects = effects || { i: _List_Nil, j: _List_Nil }; + + isCmd + ? (effects.i = _List_Cons(newEffect, effects.i)) + : (effects.j = _List_Cons(newEffect, effects.j)); + + return effects; +} + + + +// PORTS + + +function _Platform_checkPortName(name) +{ + if (_Platform_effectManagers[name]) + { + _Debug_crash(3, name) + } +} + + + +// OUTGOING PORTS + + +function _Platform_outgoingPort(name, converter) +{ + _Platform_checkPortName(name); + _Platform_effectManagers[name] = { + e: _Platform_outgoingPortMap, + u: converter, + a: _Platform_setupOutgoingPort + }; + return _Platform_leaf(name); +} + + +var _Platform_outgoingPortMap = F2(function(tagger, value) { return value; }); + + +function _Platform_setupOutgoingPort(name) +{ + var subs = []; + var converter = _Platform_effectManagers[name].u; + + // CREATE MANAGER + + var init = _Process_sleep(0); + + _Platform_effectManagers[name].b = init; + _Platform_effectManagers[name].c = F3(function(router, cmdList, state) + { + for ( ; cmdList.b; cmdList = cmdList.b) // WHILE_CONS + { + // grab a separate reference to subs in case unsubscribe is called + var currentSubs = subs; + var value = _Json_unwrap(converter(cmdList.a)); + for (var i = 0; i < currentSubs.length; i++) + { + currentSubs[i](value); + } + } + return init; + }); + + // PUBLIC API + + function subscribe(callback) + { + subs.push(callback); + } + + function unsubscribe(callback) + { + // copy subs into a new array in case unsubscribe is called within a + // subscribed callback + subs = subs.slice(); + var index = subs.indexOf(callback); + if (index >= 0) + { + subs.splice(index, 1); + } + } + + return { + subscribe: subscribe, + unsubscribe: unsubscribe + }; +} + + + +// INCOMING PORTS + + +function _Platform_incomingPort(name, converter) +{ + _Platform_checkPortName(name); + _Platform_effectManagers[name] = { + f: _Platform_incomingPortMap, + u: converter, + a: _Platform_setupIncomingPort + }; + return _Platform_leaf(name); +} + + +var _Platform_incomingPortMap = F2(function(tagger, finalTagger) +{ + return function(value) + { + return tagger(finalTagger(value)); + }; +}); + + +function _Platform_setupIncomingPort(name, sendToApp) +{ + var subs = _List_Nil; + var converter = _Platform_effectManagers[name].u; + + // CREATE MANAGER + + var init = _Scheduler_succeed(null); + + _Platform_effectManagers[name].b = init; + _Platform_effectManagers[name].c = F3(function(router, subList, state) + { + subs = subList; + return init; + }); + + // PUBLIC API + + function send(incomingValue) + { + var result = A2(_Json_run, converter, _Json_wrap(incomingValue)); + + $elm$core$Result$isOk(result) || _Debug_crash(4, name, result.a); + + var value = result.a; + for (var temp = subs; temp.b; temp = temp.b) // WHILE_CONS + { + sendToApp(temp.a(value)); + } + } + + return { send: send }; +} + + + +// EXPORT ELM MODULES +// +// Have DEBUG and PROD versions so that we can (1) give nicer errors in +// debug mode and (2) not pay for the bits needed for that in prod mode. +// + + +function _Platform_export_UNUSED(exports) +{ + scope['Elm'] + ? _Platform_mergeExportsProd(scope['Elm'], exports) + : scope['Elm'] = exports; +} + + +function _Platform_mergeExportsProd(obj, exports) +{ + for (var name in exports) + { + (name in obj) + ? (name == 'init') + ? _Debug_crash(6) + : _Platform_mergeExportsProd(obj[name], exports[name]) + : (obj[name] = exports[name]); + } +} + + +function _Platform_export(exports) +{ + scope['Elm'] + ? _Platform_mergeExportsDebug('Elm', scope['Elm'], exports) + : scope['Elm'] = exports; +} + + +function _Platform_mergeExportsDebug(moduleName, obj, exports) +{ + for (var name in exports) + { + (name in obj) + ? (name == 'init') + ? _Debug_crash(6, moduleName) + : _Platform_mergeExportsDebug(moduleName + '.' + name, obj[name], exports[name]) + : (obj[name] = exports[name]); + } +} + + + + +// HELPERS + + +var _VirtualDom_divertHrefToApp; + +var _VirtualDom_doc = typeof document !== 'undefined' ? document : {}; + + +function _VirtualDom_appendChild(parent, child) +{ + parent.appendChild(child); +} + +var _VirtualDom_init = F4(function(virtualNode, flagDecoder, debugMetadata, args) +{ + // NOTE: this function needs _Platform_export available to work + + /**_UNUSED/ + var node = args['node']; + //*/ + /**/ + var node = args && args['node'] ? args['node'] : _Debug_crash(0); + //*/ + + node.parentNode.replaceChild( + _VirtualDom_render(virtualNode, function() {}), + node + ); + + return {}; +}); + + + +// TEXT + + +function _VirtualDom_text(string) +{ + return { + $: 0, + a: string + }; +} + + + +// NODE + + +var _VirtualDom_nodeNS = F2(function(namespace, tag) +{ + return F2(function(factList, kidList) + { + for (var kids = [], descendantsCount = 0; kidList.b; kidList = kidList.b) // WHILE_CONS + { + var kid = kidList.a; + descendantsCount += (kid.b || 0); + kids.push(kid); + } + descendantsCount += kids.length; + + return { + $: 1, + c: tag, + d: _VirtualDom_organizeFacts(factList), + e: kids, + f: namespace, + b: descendantsCount + }; + }); +}); + + +var _VirtualDom_node = _VirtualDom_nodeNS(undefined); + + + +// KEYED NODE + + +var _VirtualDom_keyedNodeNS = F2(function(namespace, tag) +{ + return F2(function(factList, kidList) + { + for (var kids = [], descendantsCount = 0; kidList.b; kidList = kidList.b) // WHILE_CONS + { + var kid = kidList.a; + descendantsCount += (kid.b.b || 0); + kids.push(kid); + } + descendantsCount += kids.length; + + return { + $: 2, + c: tag, + d: _VirtualDom_organizeFacts(factList), + e: kids, + f: namespace, + b: descendantsCount + }; + }); +}); + + +var _VirtualDom_keyedNode = _VirtualDom_keyedNodeNS(undefined); + + + +// CUSTOM + + +function _VirtualDom_custom(factList, model, render, diff) +{ + return { + $: 3, + d: _VirtualDom_organizeFacts(factList), + g: model, + h: render, + i: diff + }; +} + + + +// MAP + + +var _VirtualDom_map = F2(function(tagger, node) +{ + return { + $: 4, + j: tagger, + k: node, + b: 1 + (node.b || 0) + }; +}); + + + +// LAZY + + +function _VirtualDom_thunk(refs, thunk) +{ + return { + $: 5, + l: refs, + m: thunk, + k: undefined + }; +} + +var _VirtualDom_lazy = F2(function(func, a) +{ + return _VirtualDom_thunk([func, a], function() { + return func(a); + }); +}); + +var _VirtualDom_lazy2 = F3(function(func, a, b) +{ + return _VirtualDom_thunk([func, a, b], function() { + return A2(func, a, b); + }); +}); + +var _VirtualDom_lazy3 = F4(function(func, a, b, c) +{ + return _VirtualDom_thunk([func, a, b, c], function() { + return A3(func, a, b, c); + }); +}); + +var _VirtualDom_lazy4 = F5(function(func, a, b, c, d) +{ + return _VirtualDom_thunk([func, a, b, c, d], function() { + return A4(func, a, b, c, d); + }); +}); + +var _VirtualDom_lazy5 = F6(function(func, a, b, c, d, e) +{ + return _VirtualDom_thunk([func, a, b, c, d, e], function() { + return A5(func, a, b, c, d, e); + }); +}); + +var _VirtualDom_lazy6 = F7(function(func, a, b, c, d, e, f) +{ + return _VirtualDom_thunk([func, a, b, c, d, e, f], function() { + return A6(func, a, b, c, d, e, f); + }); +}); + +var _VirtualDom_lazy7 = F8(function(func, a, b, c, d, e, f, g) +{ + return _VirtualDom_thunk([func, a, b, c, d, e, f, g], function() { + return A7(func, a, b, c, d, e, f, g); + }); +}); + +var _VirtualDom_lazy8 = F9(function(func, a, b, c, d, e, f, g, h) +{ + return _VirtualDom_thunk([func, a, b, c, d, e, f, g, h], function() { + return A8(func, a, b, c, d, e, f, g, h); + }); +}); + + + +// FACTS + + +var _VirtualDom_on = F2(function(key, handler) +{ + return { + $: 'a0', + n: key, + o: handler + }; +}); +var _VirtualDom_style = F2(function(key, value) +{ + return { + $: 'a1', + n: key, + o: value + }; +}); +var _VirtualDom_property = F2(function(key, value) +{ + return { + $: 'a2', + n: key, + o: value + }; +}); +var _VirtualDom_attribute = F2(function(key, value) +{ + return { + $: 'a3', + n: key, + o: value + }; +}); +var _VirtualDom_attributeNS = F3(function(namespace, key, value) +{ + return { + $: 'a4', + n: key, + o: { f: namespace, o: value } + }; +}); + + + +// XSS ATTACK VECTOR CHECKS +// +// For some reason, tabs can appear in href protocols and it still works. +// So '\tjava\tSCRIPT:alert("!!!")' and 'javascript:alert("!!!")' are the same +// in practice. That is why _VirtualDom_RE_js and _VirtualDom_RE_js_html look +// so freaky. +// +// Pulling the regular expressions out to the top level gives a slight speed +// boost in small benchmarks (4-10%) but hoisting values to reduce allocation +// can be unpredictable in large programs where JIT may have a harder time with +// functions are not fully self-contained. The benefit is more that the js and +// js_html ones are so weird that I prefer to see them near each other. + + +var _VirtualDom_RE_script = /^script$/i; +var _VirtualDom_RE_on_formAction = /^(on|formAction$)/i; +var _VirtualDom_RE_js = /^\s*j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t\s*:/i; +var _VirtualDom_RE_js_html = /^\s*(j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t\s*:|d\s*a\s*t\s*a\s*:\s*t\s*e\s*x\s*t\s*\/\s*h\s*t\s*m\s*l\s*(,|;))/i; + + +function _VirtualDom_noScript(tag) +{ + return _VirtualDom_RE_script.test(tag) ? 'p' : tag; +} + +function _VirtualDom_noOnOrFormAction(key) +{ + return _VirtualDom_RE_on_formAction.test(key) ? 'data-' + key : key; +} + +function _VirtualDom_noInnerHtmlOrFormAction(key) +{ + return key == 'innerHTML' || key == 'formAction' ? 'data-' + key : key; +} + +function _VirtualDom_noJavaScriptUri(value) +{ + return _VirtualDom_RE_js.test(value) + ? /**_UNUSED/''//*//**/'javascript:alert("This is an XSS vector. Please use ports or web components instead.")'//*/ + : value; +} + +function _VirtualDom_noJavaScriptOrHtmlUri(value) +{ + return _VirtualDom_RE_js_html.test(value) + ? /**_UNUSED/''//*//**/'javascript:alert("This is an XSS vector. Please use ports or web components instead.")'//*/ + : value; +} + +function _VirtualDom_noJavaScriptOrHtmlJson(value) +{ + return (typeof _Json_unwrap(value) === 'string' && _VirtualDom_RE_js_html.test(_Json_unwrap(value))) + ? _Json_wrap( + /**_UNUSED/''//*//**/'javascript:alert("This is an XSS vector. Please use ports or web components instead.")'//*/ + ) : value; +} + + + +// MAP FACTS + + +var _VirtualDom_mapAttribute = F2(function(func, attr) +{ + return (attr.$ === 'a0') + ? A2(_VirtualDom_on, attr.n, _VirtualDom_mapHandler(func, attr.o)) + : attr; +}); + +function _VirtualDom_mapHandler(func, handler) +{ + var tag = $elm$virtual_dom$VirtualDom$toHandlerInt(handler); + + // 0 = Normal + // 1 = MayStopPropagation + // 2 = MayPreventDefault + // 3 = Custom + + return { + $: handler.$, + a: + !tag + ? A2($elm$json$Json$Decode$map, func, handler.a) + : + A3($elm$json$Json$Decode$map2, + tag < 3 + ? _VirtualDom_mapEventTuple + : _VirtualDom_mapEventRecord, + $elm$json$Json$Decode$succeed(func), + handler.a + ) + }; +} + +var _VirtualDom_mapEventTuple = F2(function(func, tuple) +{ + return _Utils_Tuple2(func(tuple.a), tuple.b); +}); + +var _VirtualDom_mapEventRecord = F2(function(func, record) +{ + return { + message: func(record.message), + stopPropagation: record.stopPropagation, + preventDefault: record.preventDefault + } +}); + + + +// ORGANIZE FACTS + + +function _VirtualDom_organizeFacts(factList) +{ + for (var facts = {}; factList.b; factList = factList.b) // WHILE_CONS + { + var entry = factList.a; + + var tag = entry.$; + var key = entry.n; + var value = entry.o; + + if (tag === 'a2') + { + (key === 'className') + ? _VirtualDom_addClass(facts, key, _Json_unwrap(value)) + : facts[key] = _Json_unwrap(value); + + continue; + } + + var subFacts = facts[tag] || (facts[tag] = {}); + (tag === 'a3' && key === 'class') + ? _VirtualDom_addClass(subFacts, key, value) + : subFacts[key] = value; + } + + return facts; +} + +function _VirtualDom_addClass(object, key, newClass) +{ + var classes = object[key]; + object[key] = classes ? classes + ' ' + newClass : newClass; +} + + + +// RENDER + + +function _VirtualDom_render(vNode, eventNode) +{ + var tag = vNode.$; + + if (tag === 5) + { + return _VirtualDom_render(vNode.k || (vNode.k = vNode.m()), eventNode); + } + + if (tag === 0) + { + return _VirtualDom_doc.createTextNode(vNode.a); + } + + if (tag === 4) + { + var subNode = vNode.k; + var tagger = vNode.j; + + while (subNode.$ === 4) + { + typeof tagger !== 'object' + ? tagger = [tagger, subNode.j] + : tagger.push(subNode.j); + + subNode = subNode.k; + } + + var subEventRoot = { j: tagger, p: eventNode }; + var domNode = _VirtualDom_render(subNode, subEventRoot); + domNode.elm_event_node_ref = subEventRoot; + return domNode; + } + + if (tag === 3) + { + var domNode = vNode.h(vNode.g); + _VirtualDom_applyFacts(domNode, eventNode, vNode.d); + return domNode; + } + + // at this point `tag` must be 1 or 2 + + var domNode = vNode.f + ? _VirtualDom_doc.createElementNS(vNode.f, vNode.c) + : _VirtualDom_doc.createElement(vNode.c); + + if (_VirtualDom_divertHrefToApp && vNode.c == 'a') + { + domNode.addEventListener('click', _VirtualDom_divertHrefToApp(domNode)); + } + + _VirtualDom_applyFacts(domNode, eventNode, vNode.d); + + for (var kids = vNode.e, i = 0; i < kids.length; i++) + { + _VirtualDom_appendChild(domNode, _VirtualDom_render(tag === 1 ? kids[i] : kids[i].b, eventNode)); + } + + return domNode; +} + + + +// APPLY FACTS + + +function _VirtualDom_applyFacts(domNode, eventNode, facts) +{ + for (var key in facts) + { + var value = facts[key]; + + key === 'a1' + ? _VirtualDom_applyStyles(domNode, value) + : + key === 'a0' + ? _VirtualDom_applyEvents(domNode, eventNode, value) + : + key === 'a3' + ? _VirtualDom_applyAttrs(domNode, value) + : + key === 'a4' + ? _VirtualDom_applyAttrsNS(domNode, value) + : + ((key !== 'value' && key !== 'checked') || domNode[key] !== value) && (domNode[key] = value); + } +} + + + +// APPLY STYLES + + +function _VirtualDom_applyStyles(domNode, styles) +{ + var domNodeStyle = domNode.style; + + for (var key in styles) + { + domNodeStyle[key] = styles[key]; + } +} + + + +// APPLY ATTRS + + +function _VirtualDom_applyAttrs(domNode, attrs) +{ + for (var key in attrs) + { + var value = attrs[key]; + typeof value !== 'undefined' + ? domNode.setAttribute(key, value) + : domNode.removeAttribute(key); + } +} + + + +// APPLY NAMESPACED ATTRS + + +function _VirtualDom_applyAttrsNS(domNode, nsAttrs) +{ + for (var key in nsAttrs) + { + var pair = nsAttrs[key]; + var namespace = pair.f; + var value = pair.o; + + typeof value !== 'undefined' + ? domNode.setAttributeNS(namespace, key, value) + : domNode.removeAttributeNS(namespace, key); + } +} + + + +// APPLY EVENTS + + +function _VirtualDom_applyEvents(domNode, eventNode, events) +{ + var allCallbacks = domNode.elmFs || (domNode.elmFs = {}); + + for (var key in events) + { + var newHandler = events[key]; + var oldCallback = allCallbacks[key]; + + if (!newHandler) + { + domNode.removeEventListener(key, oldCallback); + allCallbacks[key] = undefined; + continue; + } + + if (oldCallback) + { + var oldHandler = oldCallback.q; + if (oldHandler.$ === newHandler.$) + { + oldCallback.q = newHandler; + continue; + } + domNode.removeEventListener(key, oldCallback); + } + + oldCallback = _VirtualDom_makeCallback(eventNode, newHandler); + domNode.addEventListener(key, oldCallback, + _VirtualDom_passiveSupported + && { passive: $elm$virtual_dom$VirtualDom$toHandlerInt(newHandler) < 2 } + ); + allCallbacks[key] = oldCallback; + } +} + + + +// PASSIVE EVENTS + + +var _VirtualDom_passiveSupported; + +try +{ + window.addEventListener('t', null, Object.defineProperty({}, 'passive', { + get: function() { _VirtualDom_passiveSupported = true; } + })); +} +catch(e) {} + + + +// EVENT HANDLERS + + +function _VirtualDom_makeCallback(eventNode, initialHandler) +{ + function callback(event) + { + var handler = callback.q; + var result = _Json_runHelp(handler.a, event); + + if (!$elm$core$Result$isOk(result)) + { + return; + } + + var tag = $elm$virtual_dom$VirtualDom$toHandlerInt(handler); + + // 0 = Normal + // 1 = MayStopPropagation + // 2 = MayPreventDefault + // 3 = Custom + + var value = result.a; + var message = !tag ? value : tag < 3 ? value.a : value.message; + var stopPropagation = tag == 1 ? value.b : tag == 3 && value.stopPropagation; + var currentEventNode = ( + stopPropagation && event.stopPropagation(), + (tag == 2 ? value.b : tag == 3 && value.preventDefault) && event.preventDefault(), + eventNode + ); + var tagger; + var i; + while (tagger = currentEventNode.j) + { + if (typeof tagger == 'function') + { + message = tagger(message); + } + else + { + for (var i = tagger.length; i--; ) + { + message = tagger[i](message); + } + } + currentEventNode = currentEventNode.p; + } + currentEventNode(message, stopPropagation); // stopPropagation implies isSync + } + + callback.q = initialHandler; + + return callback; +} + +function _VirtualDom_equalEvents(x, y) +{ + return x.$ == y.$ && _Json_equality(x.a, y.a); +} + + + +// DIFF + + +// TODO: Should we do patches like in iOS? +// +// type Patch +// = At Int Patch +// | Batch (List Patch) +// | Change ... +// +// How could it not be better? +// +function _VirtualDom_diff(x, y) +{ + var patches = []; + _VirtualDom_diffHelp(x, y, patches, 0); + return patches; +} + + +function _VirtualDom_pushPatch(patches, type, index, data) +{ + var patch = { + $: type, + r: index, + s: data, + t: undefined, + u: undefined + }; + patches.push(patch); + return patch; +} + + +function _VirtualDom_diffHelp(x, y, patches, index) +{ + if (x === y) + { + return; + } + + var xType = x.$; + var yType = y.$; + + // Bail if you run into different types of nodes. Implies that the + // structure has changed significantly and it's not worth a diff. + if (xType !== yType) + { + if (xType === 1 && yType === 2) + { + y = _VirtualDom_dekey(y); + yType = 1; + } + else + { + _VirtualDom_pushPatch(patches, 0, index, y); + return; + } + } + + // Now we know that both nodes are the same $. + switch (yType) + { + case 5: + var xRefs = x.l; + var yRefs = y.l; + var i = xRefs.length; + var same = i === yRefs.length; + while (same && i--) + { + same = xRefs[i] === yRefs[i]; + } + if (same) + { + y.k = x.k; + return; + } + y.k = y.m(); + var subPatches = []; + _VirtualDom_diffHelp(x.k, y.k, subPatches, 0); + subPatches.length > 0 && _VirtualDom_pushPatch(patches, 1, index, subPatches); + return; + + case 4: + // gather nested taggers + var xTaggers = x.j; + var yTaggers = y.j; + var nesting = false; + + var xSubNode = x.k; + while (xSubNode.$ === 4) + { + nesting = true; + + typeof xTaggers !== 'object' + ? xTaggers = [xTaggers, xSubNode.j] + : xTaggers.push(xSubNode.j); + + xSubNode = xSubNode.k; + } + + var ySubNode = y.k; + while (ySubNode.$ === 4) + { + nesting = true; + + typeof yTaggers !== 'object' + ? yTaggers = [yTaggers, ySubNode.j] + : yTaggers.push(ySubNode.j); + + ySubNode = ySubNode.k; + } + + // Just bail if different numbers of taggers. This implies the + // structure of the virtual DOM has changed. + if (nesting && xTaggers.length !== yTaggers.length) + { + _VirtualDom_pushPatch(patches, 0, index, y); + return; + } + + // check if taggers are "the same" + if (nesting ? !_VirtualDom_pairwiseRefEqual(xTaggers, yTaggers) : xTaggers !== yTaggers) + { + _VirtualDom_pushPatch(patches, 2, index, yTaggers); + } + + // diff everything below the taggers + _VirtualDom_diffHelp(xSubNode, ySubNode, patches, index + 1); + return; + + case 0: + if (x.a !== y.a) + { + _VirtualDom_pushPatch(patches, 3, index, y.a); + } + return; + + case 1: + _VirtualDom_diffNodes(x, y, patches, index, _VirtualDom_diffKids); + return; + + case 2: + _VirtualDom_diffNodes(x, y, patches, index, _VirtualDom_diffKeyedKids); + return; + + case 3: + if (x.h !== y.h) + { + _VirtualDom_pushPatch(patches, 0, index, y); + return; + } + + var factsDiff = _VirtualDom_diffFacts(x.d, y.d); + factsDiff && _VirtualDom_pushPatch(patches, 4, index, factsDiff); + + var patch = y.i(x.g, y.g); + patch && _VirtualDom_pushPatch(patches, 5, index, patch); + + return; + } +} + +// assumes the incoming arrays are the same length +function _VirtualDom_pairwiseRefEqual(as, bs) +{ + for (var i = 0; i < as.length; i++) + { + if (as[i] !== bs[i]) + { + return false; + } + } + + return true; +} + +function _VirtualDom_diffNodes(x, y, patches, index, diffKids) +{ + // Bail if obvious indicators have changed. Implies more serious + // structural changes such that it's not worth it to diff. + if (x.c !== y.c || x.f !== y.f) + { + _VirtualDom_pushPatch(patches, 0, index, y); + return; + } + + var factsDiff = _VirtualDom_diffFacts(x.d, y.d); + factsDiff && _VirtualDom_pushPatch(patches, 4, index, factsDiff); + + diffKids(x, y, patches, index); +} + + + +// DIFF FACTS + + +// TODO Instead of creating a new diff object, it's possible to just test if +// there *is* a diff. During the actual patch, do the diff again and make the +// modifications directly. This way, there's no new allocations. Worth it? +function _VirtualDom_diffFacts(x, y, category) +{ + var diff; + + // look for changes and removals + for (var xKey in x) + { + if (xKey === 'a1' || xKey === 'a0' || xKey === 'a3' || xKey === 'a4') + { + var subDiff = _VirtualDom_diffFacts(x[xKey], y[xKey] || {}, xKey); + if (subDiff) + { + diff = diff || {}; + diff[xKey] = subDiff; + } + continue; + } + + // remove if not in the new facts + if (!(xKey in y)) + { + diff = diff || {}; + diff[xKey] = + !category + ? (typeof x[xKey] === 'string' ? '' : null) + : + (category === 'a1') + ? '' + : + (category === 'a0' || category === 'a3') + ? undefined + : + { f: x[xKey].f, o: undefined }; + + continue; + } + + var xValue = x[xKey]; + var yValue = y[xKey]; + + // reference equal, so don't worry about it + if (xValue === yValue && xKey !== 'value' && xKey !== 'checked' + || category === 'a0' && _VirtualDom_equalEvents(xValue, yValue)) + { + continue; + } + + diff = diff || {}; + diff[xKey] = yValue; + } + + // add new stuff + for (var yKey in y) + { + if (!(yKey in x)) + { + diff = diff || {}; + diff[yKey] = y[yKey]; + } + } + + return diff; +} + + + +// DIFF KIDS + + +function _VirtualDom_diffKids(xParent, yParent, patches, index) +{ + var xKids = xParent.e; + var yKids = yParent.e; + + var xLen = xKids.length; + var yLen = yKids.length; + + // FIGURE OUT IF THERE ARE INSERTS OR REMOVALS + + if (xLen > yLen) + { + _VirtualDom_pushPatch(patches, 6, index, { + v: yLen, + i: xLen - yLen + }); + } + else if (xLen < yLen) + { + _VirtualDom_pushPatch(patches, 7, index, { + v: xLen, + e: yKids + }); + } + + // PAIRWISE DIFF EVERYTHING ELSE + + for (var minLen = xLen < yLen ? xLen : yLen, i = 0; i < minLen; i++) + { + var xKid = xKids[i]; + _VirtualDom_diffHelp(xKid, yKids[i], patches, ++index); + index += xKid.b || 0; + } +} + + + +// KEYED DIFF + + +function _VirtualDom_diffKeyedKids(xParent, yParent, patches, rootIndex) +{ + var localPatches = []; + + var changes = {}; // Dict String Entry + var inserts = []; // Array { index : Int, entry : Entry } + // type Entry = { tag : String, vnode : VNode, index : Int, data : _ } + + var xKids = xParent.e; + var yKids = yParent.e; + var xLen = xKids.length; + var yLen = yKids.length; + var xIndex = 0; + var yIndex = 0; + + var index = rootIndex; + + while (xIndex < xLen && yIndex < yLen) + { + var x = xKids[xIndex]; + var y = yKids[yIndex]; + + var xKey = x.a; + var yKey = y.a; + var xNode = x.b; + var yNode = y.b; + + var newMatch = undefined; + var oldMatch = undefined; + + // check if keys match + + if (xKey === yKey) + { + index++; + _VirtualDom_diffHelp(xNode, yNode, localPatches, index); + index += xNode.b || 0; + + xIndex++; + yIndex++; + continue; + } + + // look ahead 1 to detect insertions and removals. + + var xNext = xKids[xIndex + 1]; + var yNext = yKids[yIndex + 1]; + + if (xNext) + { + var xNextKey = xNext.a; + var xNextNode = xNext.b; + oldMatch = yKey === xNextKey; + } + + if (yNext) + { + var yNextKey = yNext.a; + var yNextNode = yNext.b; + newMatch = xKey === yNextKey; + } + + + // swap x and y + if (newMatch && oldMatch) + { + index++; + _VirtualDom_diffHelp(xNode, yNextNode, localPatches, index); + _VirtualDom_insertNode(changes, localPatches, xKey, yNode, yIndex, inserts); + index += xNode.b || 0; + + index++; + _VirtualDom_removeNode(changes, localPatches, xKey, xNextNode, index); + index += xNextNode.b || 0; + + xIndex += 2; + yIndex += 2; + continue; + } + + // insert y + if (newMatch) + { + index++; + _VirtualDom_insertNode(changes, localPatches, yKey, yNode, yIndex, inserts); + _VirtualDom_diffHelp(xNode, yNextNode, localPatches, index); + index += xNode.b || 0; + + xIndex += 1; + yIndex += 2; + continue; + } + + // remove x + if (oldMatch) + { + index++; + _VirtualDom_removeNode(changes, localPatches, xKey, xNode, index); + index += xNode.b || 0; + + index++; + _VirtualDom_diffHelp(xNextNode, yNode, localPatches, index); + index += xNextNode.b || 0; + + xIndex += 2; + yIndex += 1; + continue; + } + + // remove x, insert y + if (xNext && xNextKey === yNextKey) + { + index++; + _VirtualDom_removeNode(changes, localPatches, xKey, xNode, index); + _VirtualDom_insertNode(changes, localPatches, yKey, yNode, yIndex, inserts); + index += xNode.b || 0; + + index++; + _VirtualDom_diffHelp(xNextNode, yNextNode, localPatches, index); + index += xNextNode.b || 0; + + xIndex += 2; + yIndex += 2; + continue; + } + + break; + } + + // eat up any remaining nodes with removeNode and insertNode + + while (xIndex < xLen) + { + index++; + var x = xKids[xIndex]; + var xNode = x.b; + _VirtualDom_removeNode(changes, localPatches, x.a, xNode, index); + index += xNode.b || 0; + xIndex++; + } + + while (yIndex < yLen) + { + var endInserts = endInserts || []; + var y = yKids[yIndex]; + _VirtualDom_insertNode(changes, localPatches, y.a, y.b, undefined, endInserts); + yIndex++; + } + + if (localPatches.length > 0 || inserts.length > 0 || endInserts) + { + _VirtualDom_pushPatch(patches, 8, rootIndex, { + w: localPatches, + x: inserts, + y: endInserts + }); + } +} + + + +// CHANGES FROM KEYED DIFF + + +var _VirtualDom_POSTFIX = '_elmW6BL'; + + +function _VirtualDom_insertNode(changes, localPatches, key, vnode, yIndex, inserts) +{ + var entry = changes[key]; + + // never seen this key before + if (!entry) + { + entry = { + c: 0, + z: vnode, + r: yIndex, + s: undefined + }; + + inserts.push({ r: yIndex, A: entry }); + changes[key] = entry; + + return; + } + + // this key was removed earlier, a match! + if (entry.c === 1) + { + inserts.push({ r: yIndex, A: entry }); + + entry.c = 2; + var subPatches = []; + _VirtualDom_diffHelp(entry.z, vnode, subPatches, entry.r); + entry.r = yIndex; + entry.s.s = { + w: subPatches, + A: entry + }; + + return; + } + + // this key has already been inserted or moved, a duplicate! + _VirtualDom_insertNode(changes, localPatches, key + _VirtualDom_POSTFIX, vnode, yIndex, inserts); +} + + +function _VirtualDom_removeNode(changes, localPatches, key, vnode, index) +{ + var entry = changes[key]; + + // never seen this key before + if (!entry) + { + var patch = _VirtualDom_pushPatch(localPatches, 9, index, undefined); + + changes[key] = { + c: 1, + z: vnode, + r: index, + s: patch + }; + + return; + } + + // this key was inserted earlier, a match! + if (entry.c === 0) + { + entry.c = 2; + var subPatches = []; + _VirtualDom_diffHelp(vnode, entry.z, subPatches, index); + + _VirtualDom_pushPatch(localPatches, 9, index, { + w: subPatches, + A: entry + }); + + return; + } + + // this key has already been removed or moved, a duplicate! + _VirtualDom_removeNode(changes, localPatches, key + _VirtualDom_POSTFIX, vnode, index); +} + + + +// ADD DOM NODES +// +// Each DOM node has an "index" assigned in order of traversal. It is important +// to minimize our crawl over the actual DOM, so these indexes (along with the +// descendantsCount of virtual nodes) let us skip touching entire subtrees of +// the DOM if we know there are no patches there. + + +function _VirtualDom_addDomNodes(domNode, vNode, patches, eventNode) +{ + _VirtualDom_addDomNodesHelp(domNode, vNode, patches, 0, 0, vNode.b, eventNode); +} + + +// assumes `patches` is non-empty and indexes increase monotonically. +function _VirtualDom_addDomNodesHelp(domNode, vNode, patches, i, low, high, eventNode) +{ + var patch = patches[i]; + var index = patch.r; + + while (index === low) + { + var patchType = patch.$; + + if (patchType === 1) + { + _VirtualDom_addDomNodes(domNode, vNode.k, patch.s, eventNode); + } + else if (patchType === 8) + { + patch.t = domNode; + patch.u = eventNode; + + var subPatches = patch.s.w; + if (subPatches.length > 0) + { + _VirtualDom_addDomNodesHelp(domNode, vNode, subPatches, 0, low, high, eventNode); + } + } + else if (patchType === 9) + { + patch.t = domNode; + patch.u = eventNode; + + var data = patch.s; + if (data) + { + data.A.s = domNode; + var subPatches = data.w; + if (subPatches.length > 0) + { + _VirtualDom_addDomNodesHelp(domNode, vNode, subPatches, 0, low, high, eventNode); + } + } + } + else + { + patch.t = domNode; + patch.u = eventNode; + } + + i++; + + if (!(patch = patches[i]) || (index = patch.r) > high) + { + return i; + } + } + + var tag = vNode.$; + + if (tag === 4) + { + var subNode = vNode.k; + + while (subNode.$ === 4) + { + subNode = subNode.k; + } + + return _VirtualDom_addDomNodesHelp(domNode, subNode, patches, i, low + 1, high, domNode.elm_event_node_ref); + } + + // tag must be 1 or 2 at this point + + var vKids = vNode.e; + var childNodes = domNode.childNodes; + for (var j = 0; j < vKids.length; j++) + { + low++; + var vKid = tag === 1 ? vKids[j] : vKids[j].b; + var nextLow = low + (vKid.b || 0); + if (low <= index && index <= nextLow) + { + i = _VirtualDom_addDomNodesHelp(childNodes[j], vKid, patches, i, low, nextLow, eventNode); + if (!(patch = patches[i]) || (index = patch.r) > high) + { + return i; + } + } + low = nextLow; + } + return i; +} + + + +// APPLY PATCHES + + +function _VirtualDom_applyPatches(rootDomNode, oldVirtualNode, patches, eventNode) +{ + if (patches.length === 0) + { + return rootDomNode; + } + + _VirtualDom_addDomNodes(rootDomNode, oldVirtualNode, patches, eventNode); + return _VirtualDom_applyPatchesHelp(rootDomNode, patches); +} + +function _VirtualDom_applyPatchesHelp(rootDomNode, patches) +{ + for (var i = 0; i < patches.length; i++) + { + var patch = patches[i]; + var localDomNode = patch.t + var newNode = _VirtualDom_applyPatch(localDomNode, patch); + if (localDomNode === rootDomNode) + { + rootDomNode = newNode; + } + } + return rootDomNode; +} + +function _VirtualDom_applyPatch(domNode, patch) +{ + switch (patch.$) + { + case 0: + return _VirtualDom_applyPatchRedraw(domNode, patch.s, patch.u); + + case 4: + _VirtualDom_applyFacts(domNode, patch.u, patch.s); + return domNode; + + case 3: + domNode.replaceData(0, domNode.length, patch.s); + return domNode; + + case 1: + return _VirtualDom_applyPatchesHelp(domNode, patch.s); + + case 2: + if (domNode.elm_event_node_ref) + { + domNode.elm_event_node_ref.j = patch.s; + } + else + { + domNode.elm_event_node_ref = { j: patch.s, p: patch.u }; + } + return domNode; + + case 6: + var data = patch.s; + for (var i = 0; i < data.i; i++) + { + domNode.removeChild(domNode.childNodes[data.v]); + } + return domNode; + + case 7: + var data = patch.s; + var kids = data.e; + var i = data.v; + var theEnd = domNode.childNodes[i]; + for (; i < kids.length; i++) + { + domNode.insertBefore(_VirtualDom_render(kids[i], patch.u), theEnd); + } + return domNode; + + case 9: + var data = patch.s; + if (!data) + { + domNode.parentNode.removeChild(domNode); + return domNode; + } + var entry = data.A; + if (typeof entry.r !== 'undefined') + { + domNode.parentNode.removeChild(domNode); + } + entry.s = _VirtualDom_applyPatchesHelp(domNode, data.w); + return domNode; + + case 8: + return _VirtualDom_applyPatchReorder(domNode, patch); + + case 5: + return patch.s(domNode); + + default: + _Debug_crash(10); // 'Ran into an unknown patch!' + } +} + + +function _VirtualDom_applyPatchRedraw(domNode, vNode, eventNode) +{ + var parentNode = domNode.parentNode; + var newNode = _VirtualDom_render(vNode, eventNode); + + if (!newNode.elm_event_node_ref) + { + newNode.elm_event_node_ref = domNode.elm_event_node_ref; + } + + if (parentNode && newNode !== domNode) + { + parentNode.replaceChild(newNode, domNode); + } + return newNode; +} + + +function _VirtualDom_applyPatchReorder(domNode, patch) +{ + var data = patch.s; + + // remove end inserts + var frag = _VirtualDom_applyPatchReorderEndInsertsHelp(data.y, patch); + + // removals + domNode = _VirtualDom_applyPatchesHelp(domNode, data.w); + + // inserts + var inserts = data.x; + for (var i = 0; i < inserts.length; i++) + { + var insert = inserts[i]; + var entry = insert.A; + var node = entry.c === 2 + ? entry.s + : _VirtualDom_render(entry.z, patch.u); + domNode.insertBefore(node, domNode.childNodes[insert.r]); + } + + // add end inserts + if (frag) + { + _VirtualDom_appendChild(domNode, frag); + } + + return domNode; +} + + +function _VirtualDom_applyPatchReorderEndInsertsHelp(endInserts, patch) +{ + if (!endInserts) + { + return; + } + + var frag = _VirtualDom_doc.createDocumentFragment(); + for (var i = 0; i < endInserts.length; i++) + { + var insert = endInserts[i]; + var entry = insert.A; + _VirtualDom_appendChild(frag, entry.c === 2 + ? entry.s + : _VirtualDom_render(entry.z, patch.u) + ); + } + return frag; +} + + +function _VirtualDom_virtualize(node) +{ + // TEXT NODES + + if (node.nodeType === 3) + { + return _VirtualDom_text(node.textContent); + } + + + // WEIRD NODES + + if (node.nodeType !== 1) + { + return _VirtualDom_text(''); + } + + + // ELEMENT NODES + + var attrList = _List_Nil; + var attrs = node.attributes; + for (var i = attrs.length; i--; ) + { + var attr = attrs[i]; + var name = attr.name; + var value = attr.value; + attrList = _List_Cons( A2(_VirtualDom_attribute, name, value), attrList ); + } + + var tag = node.tagName.toLowerCase(); + var kidList = _List_Nil; + var kids = node.childNodes; + + for (var i = kids.length; i--; ) + { + kidList = _List_Cons(_VirtualDom_virtualize(kids[i]), kidList); + } + return A3(_VirtualDom_node, tag, attrList, kidList); +} + +function _VirtualDom_dekey(keyedNode) +{ + var keyedKids = keyedNode.e; + var len = keyedKids.length; + var kids = new Array(len); + for (var i = 0; i < len; i++) + { + kids[i] = keyedKids[i].b; + } + + return { + $: 1, + c: keyedNode.c, + d: keyedNode.d, + e: kids, + f: keyedNode.f, + b: keyedNode.b + }; +} + + + + +// ELEMENT + + +var _Debugger_element; + +var _Browser_element = _Debugger_element || F4(function(impl, flagDecoder, debugMetadata, args) +{ + return _Platform_initialize( + flagDecoder, + args, + impl.init, + impl.update, + impl.subscriptions, + function(sendToApp, initialModel) { + var view = impl.view; + /**_UNUSED/ + var domNode = args['node']; + //*/ + /**/ + var domNode = args && args['node'] ? args['node'] : _Debug_crash(0); + //*/ + var currNode = _VirtualDom_virtualize(domNode); + + return _Browser_makeAnimator(initialModel, function(model) + { + var nextNode = view(model); + var patches = _VirtualDom_diff(currNode, nextNode); + domNode = _VirtualDom_applyPatches(domNode, currNode, patches, sendToApp); + currNode = nextNode; + }); + } + ); +}); + + + +// DOCUMENT + + +var _Debugger_document; + +var _Browser_document = _Debugger_document || F4(function(impl, flagDecoder, debugMetadata, args) +{ + return _Platform_initialize( + flagDecoder, + args, + impl.init, + impl.update, + impl.subscriptions, + function(sendToApp, initialModel) { + var divertHrefToApp = impl.setup && impl.setup(sendToApp) + var view = impl.view; + var title = _VirtualDom_doc.title; + var bodyNode = _VirtualDom_doc.body; + var currNode = _VirtualDom_virtualize(bodyNode); + return _Browser_makeAnimator(initialModel, function(model) + { + _VirtualDom_divertHrefToApp = divertHrefToApp; + var doc = view(model); + var nextNode = _VirtualDom_node('body')(_List_Nil)(doc.body); + var patches = _VirtualDom_diff(currNode, nextNode); + bodyNode = _VirtualDom_applyPatches(bodyNode, currNode, patches, sendToApp); + currNode = nextNode; + _VirtualDom_divertHrefToApp = 0; + (title !== doc.title) && (_VirtualDom_doc.title = title = doc.title); + }); + } + ); +}); + + + +// ANIMATION + + +var _Browser_cancelAnimationFrame = + typeof cancelAnimationFrame !== 'undefined' + ? cancelAnimationFrame + : function(id) { clearTimeout(id); }; + +var _Browser_requestAnimationFrame = + typeof requestAnimationFrame !== 'undefined' + ? requestAnimationFrame + : function(callback) { return setTimeout(callback, 1000 / 60); }; + + +function _Browser_makeAnimator(model, draw) +{ + draw(model); + + var state = 0; + + function updateIfNeeded() + { + state = state === 1 + ? 0 + : ( _Browser_requestAnimationFrame(updateIfNeeded), draw(model), 1 ); + } + + return function(nextModel, isSync) + { + model = nextModel; + + isSync + ? ( draw(model), + state === 2 && (state = 1) + ) + : ( state === 0 && _Browser_requestAnimationFrame(updateIfNeeded), + state = 2 + ); + }; +} + + + +// APPLICATION + + +function _Browser_application(impl) +{ + var onUrlChange = impl.onUrlChange; + var onUrlRequest = impl.onUrlRequest; + var key = function() { key.a(onUrlChange(_Browser_getUrl())); }; + + return _Browser_document({ + setup: function(sendToApp) + { + key.a = sendToApp; + _Browser_window.addEventListener('popstate', key); + _Browser_window.navigator.userAgent.indexOf('Trident') < 0 || _Browser_window.addEventListener('hashchange', key); + + return F2(function(domNode, event) + { + if (!event.ctrlKey && !event.metaKey && !event.shiftKey && event.button < 1 && !domNode.target && !domNode.hasAttribute('download')) + { + event.preventDefault(); + var href = domNode.href; + var curr = _Browser_getUrl(); + var next = $elm$url$Url$fromString(href).a; + sendToApp(onUrlRequest( + (next + && curr.protocol === next.protocol + && curr.host === next.host + && curr.port_.a === next.port_.a + ) + ? $elm$browser$Browser$Internal(next) + : $elm$browser$Browser$External(href) + )); + } + }); + }, + init: function(flags) + { + return A3(impl.init, flags, _Browser_getUrl(), key); + }, + view: impl.view, + update: impl.update, + subscriptions: impl.subscriptions + }); +} + +function _Browser_getUrl() +{ + return $elm$url$Url$fromString(_VirtualDom_doc.location.href).a || _Debug_crash(1); +} + +var _Browser_go = F2(function(key, n) +{ + return A2($elm$core$Task$perform, $elm$core$Basics$never, _Scheduler_binding(function() { + n && history.go(n); + key(); + })); +}); + +var _Browser_pushUrl = F2(function(key, url) +{ + return A2($elm$core$Task$perform, $elm$core$Basics$never, _Scheduler_binding(function() { + history.pushState({}, '', url); + key(); + })); +}); + +var _Browser_replaceUrl = F2(function(key, url) +{ + return A2($elm$core$Task$perform, $elm$core$Basics$never, _Scheduler_binding(function() { + history.replaceState({}, '', url); + key(); + })); +}); + + + +// GLOBAL EVENTS + + +var _Browser_fakeNode = { addEventListener: function() {}, removeEventListener: function() {} }; +var _Browser_doc = typeof document !== 'undefined' ? document : _Browser_fakeNode; +var _Browser_window = typeof window !== 'undefined' ? window : _Browser_fakeNode; + +var _Browser_on = F3(function(node, eventName, sendToSelf) +{ + return _Scheduler_spawn(_Scheduler_binding(function(callback) + { + function handler(event) { _Scheduler_rawSpawn(sendToSelf(event)); } + node.addEventListener(eventName, handler, _VirtualDom_passiveSupported && { passive: true }); + return function() { node.removeEventListener(eventName, handler); }; + })); +}); + +var _Browser_decodeEvent = F2(function(decoder, event) +{ + var result = _Json_runHelp(decoder, event); + return $elm$core$Result$isOk(result) ? $elm$core$Maybe$Just(result.a) : $elm$core$Maybe$Nothing; +}); + + + +// PAGE VISIBILITY + + +function _Browser_visibilityInfo() +{ + return (typeof _VirtualDom_doc.hidden !== 'undefined') + ? { hidden: 'hidden', change: 'visibilitychange' } + : + (typeof _VirtualDom_doc.mozHidden !== 'undefined') + ? { hidden: 'mozHidden', change: 'mozvisibilitychange' } + : + (typeof _VirtualDom_doc.msHidden !== 'undefined') + ? { hidden: 'msHidden', change: 'msvisibilitychange' } + : + (typeof _VirtualDom_doc.webkitHidden !== 'undefined') + ? { hidden: 'webkitHidden', change: 'webkitvisibilitychange' } + : { hidden: 'hidden', change: 'visibilitychange' }; +} + + + +// ANIMATION FRAMES + + +function _Browser_rAF() +{ + return _Scheduler_binding(function(callback) + { + var id = _Browser_requestAnimationFrame(function() { + callback(_Scheduler_succeed(Date.now())); + }); + + return function() { + _Browser_cancelAnimationFrame(id); + }; + }); +} + + +function _Browser_now() +{ + return _Scheduler_binding(function(callback) + { + callback(_Scheduler_succeed(Date.now())); + }); +} + + + +// DOM STUFF + + +function _Browser_withNode(id, doStuff) +{ + return _Scheduler_binding(function(callback) + { + _Browser_requestAnimationFrame(function() { + var node = document.getElementById(id); + callback(node + ? _Scheduler_succeed(doStuff(node)) + : _Scheduler_fail($elm$browser$Browser$Dom$NotFound(id)) + ); + }); + }); +} + + +function _Browser_withWindow(doStuff) +{ + return _Scheduler_binding(function(callback) + { + _Browser_requestAnimationFrame(function() { + callback(_Scheduler_succeed(doStuff())); + }); + }); +} + + +// FOCUS and BLUR + + +var _Browser_call = F2(function(functionName, id) +{ + return _Browser_withNode(id, function(node) { + node[functionName](); + return _Utils_Tuple0; + }); +}); + + + +// WINDOW VIEWPORT + + +function _Browser_getViewport() +{ + return { + scene: _Browser_getScene(), + viewport: { + x: _Browser_window.pageXOffset, + y: _Browser_window.pageYOffset, + width: _Browser_doc.documentElement.clientWidth, + height: _Browser_doc.documentElement.clientHeight + } + }; +} + +function _Browser_getScene() +{ + var body = _Browser_doc.body; + var elem = _Browser_doc.documentElement; + return { + width: Math.max(body.scrollWidth, body.offsetWidth, elem.scrollWidth, elem.offsetWidth, elem.clientWidth), + height: Math.max(body.scrollHeight, body.offsetHeight, elem.scrollHeight, elem.offsetHeight, elem.clientHeight) + }; +} + +var _Browser_setViewport = F2(function(x, y) +{ + return _Browser_withWindow(function() + { + _Browser_window.scroll(x, y); + return _Utils_Tuple0; + }); +}); + + + +// ELEMENT VIEWPORT + + +function _Browser_getViewportOf(id) +{ + return _Browser_withNode(id, function(node) + { + return { + scene: { + width: node.scrollWidth, + height: node.scrollHeight + }, + viewport: { + x: node.scrollLeft, + y: node.scrollTop, + width: node.clientWidth, + height: node.clientHeight + } + }; + }); +} + + +var _Browser_setViewportOf = F3(function(id, x, y) +{ + return _Browser_withNode(id, function(node) + { + node.scrollLeft = x; + node.scrollTop = y; + return _Utils_Tuple0; + }); +}); + + + +// ELEMENT + + +function _Browser_getElement(id) +{ + return _Browser_withNode(id, function(node) + { + var rect = node.getBoundingClientRect(); + var x = _Browser_window.pageXOffset; + var y = _Browser_window.pageYOffset; + return { + scene: _Browser_getScene(), + viewport: { + x: x, + y: y, + width: _Browser_doc.documentElement.clientWidth, + height: _Browser_doc.documentElement.clientHeight + }, + element: { + x: x + rect.left, + y: y + rect.top, + width: rect.width, + height: rect.height + } + }; + }); +} + + + +// LOAD and RELOAD + + +function _Browser_reload(skipCache) +{ + return A2($elm$core$Task$perform, $elm$core$Basics$never, _Scheduler_binding(function(callback) + { + _VirtualDom_doc.location.reload(skipCache); + })); +} + +function _Browser_load(url) +{ + return A2($elm$core$Task$perform, $elm$core$Basics$never, _Scheduler_binding(function(callback) + { + try + { + _Browser_window.location = url; + } + catch(err) + { + // Only Firefox can throw a NS_ERROR_MALFORMED_URI exception here. + // Other browsers reload the page, so let's be consistent about that. + _VirtualDom_doc.location.reload(false); + } + })); +} + + + +var _Bitwise_and = F2(function(a, b) +{ + return a & b; +}); + +var _Bitwise_or = F2(function(a, b) +{ + return a | b; +}); + +var _Bitwise_xor = F2(function(a, b) +{ + return a ^ b; +}); + +function _Bitwise_complement(a) +{ + return ~a; +}; + +var _Bitwise_shiftLeftBy = F2(function(offset, a) +{ + return a << offset; +}); + +var _Bitwise_shiftRightBy = F2(function(offset, a) +{ + return a >> offset; +}); + +var _Bitwise_shiftRightZfBy = F2(function(offset, a) +{ + return a >>> offset; +}); + + + +function _Time_now(millisToPosix) +{ + return _Scheduler_binding(function(callback) + { + callback(_Scheduler_succeed(millisToPosix(Date.now()))); + }); +} + +var _Time_setInterval = F2(function(interval, task) +{ + return _Scheduler_binding(function(callback) + { + var id = setInterval(function() { _Scheduler_rawSpawn(task); }, interval); + return function() { clearInterval(id); }; + }); +}); + +function _Time_here() +{ + return _Scheduler_binding(function(callback) + { + callback(_Scheduler_succeed( + A2($elm$time$Time$customZone, -(new Date().getTimezoneOffset()), _List_Nil) + )); + }); +} + + +function _Time_getZoneName() +{ + return _Scheduler_binding(function(callback) + { + try + { + var name = $elm$time$Time$Name(Intl.DateTimeFormat().resolvedOptions().timeZone); + } + catch (e) + { + var name = $elm$time$Time$Offset(new Date().getTimezoneOffset()); + } + callback(_Scheduler_succeed(name)); + }); +} + + + + +// STRINGS + + +var _Parser_isSubString = F5(function(smallString, offset, row, col, bigString) +{ + var smallLength = smallString.length; + var isGood = offset + smallLength <= bigString.length; + + for (var i = 0; isGood && i < smallLength; ) + { + var code = bigString.charCodeAt(offset); + isGood = + smallString[i++] === bigString[offset++] + && ( + code === 0x000A /* \n */ + ? ( row++, col=1 ) + : ( col++, (code & 0xF800) === 0xD800 ? smallString[i++] === bigString[offset++] : 1 ) + ) + } + + return _Utils_Tuple3(isGood ? offset : -1, row, col); +}); + + + +// CHARS + + +var _Parser_isSubChar = F3(function(predicate, offset, string) +{ + return ( + string.length <= offset + ? -1 + : + (string.charCodeAt(offset) & 0xF800) === 0xD800 + ? (predicate(_Utils_chr(string.substr(offset, 2))) ? offset + 2 : -1) + : + (predicate(_Utils_chr(string[offset])) + ? ((string[offset] === '\n') ? -2 : (offset + 1)) + : -1 + ) + ); +}); + + +var _Parser_isAsciiCode = F3(function(code, offset, string) +{ + return string.charCodeAt(offset) === code; +}); + + + +// NUMBERS + + +var _Parser_chompBase10 = F2(function(offset, string) +{ + for (; offset < string.length; offset++) + { + var code = string.charCodeAt(offset); + if (code < 0x30 || 0x39 < code) + { + return offset; + } + } + return offset; +}); + + +var _Parser_consumeBase = F3(function(base, offset, string) +{ + for (var total = 0; offset < string.length; offset++) + { + var digit = string.charCodeAt(offset) - 0x30; + if (digit < 0 || base <= digit) break; + total = base * total + digit; + } + return _Utils_Tuple2(offset, total); +}); + + +var _Parser_consumeBase16 = F2(function(offset, string) +{ + for (var total = 0; offset < string.length; offset++) + { + var code = string.charCodeAt(offset); + if (0x30 <= code && code <= 0x39) + { + total = 16 * total + code - 0x30; + } + else if (0x41 <= code && code <= 0x46) + { + total = 16 * total + code - 55; + } + else if (0x61 <= code && code <= 0x66) + { + total = 16 * total + code - 87; + } + else + { + break; + } + } + return _Utils_Tuple2(offset, total); +}); + + + +// FIND STRING + + +var _Parser_findSubString = F5(function(smallString, offset, row, col, bigString) +{ + var newOffset = bigString.indexOf(smallString, offset); + var target = newOffset < 0 ? bigString.length : newOffset + smallString.length; + + while (offset < target) + { + var code = bigString.charCodeAt(offset++); + code === 0x000A /* \n */ + ? ( col=1, row++ ) + : ( col++, (code & 0xF800) === 0xD800 && offset++ ) + } + + return _Utils_Tuple3(newOffset, row, col); +}); +var $elm$core$Basics$EQ = {$: 'EQ'}; +var $elm$core$Basics$GT = {$: 'GT'}; +var $elm$core$Basics$LT = {$: 'LT'}; +var $elm$core$List$cons = _List_cons; +var $elm$core$Dict$foldr = F3( + function (func, acc, t) { + foldr: + while (true) { + if (t.$ === 'RBEmpty_elm_builtin') { + return acc; + } else { + var key = t.b; + var value = t.c; + var left = t.d; + var right = t.e; + var $temp$func = func, + $temp$acc = A3( + func, + key, + value, + A3($elm$core$Dict$foldr, func, acc, right)), + $temp$t = left; + func = $temp$func; + acc = $temp$acc; + t = $temp$t; + continue foldr; + } + } + }); +var $elm$core$Dict$toList = function (dict) { + return A3( + $elm$core$Dict$foldr, + F3( + function (key, value, list) { + return A2( + $elm$core$List$cons, + _Utils_Tuple2(key, value), + list); + }), + _List_Nil, + dict); +}; +var $elm$core$Dict$keys = function (dict) { + return A3( + $elm$core$Dict$foldr, + F3( + function (key, value, keyList) { + return A2($elm$core$List$cons, key, keyList); + }), + _List_Nil, + dict); +}; +var $elm$core$Set$toList = function (_v0) { + var dict = _v0.a; + return $elm$core$Dict$keys(dict); +}; +var $elm$core$Elm$JsArray$foldr = _JsArray_foldr; +var $elm$core$Array$foldr = F3( + function (func, baseCase, _v0) { + var tree = _v0.c; + var tail = _v0.d; + var helper = F2( + function (node, acc) { + if (node.$ === 'SubTree') { + var subTree = node.a; + return A3($elm$core$Elm$JsArray$foldr, helper, acc, subTree); + } else { + var values = node.a; + return A3($elm$core$Elm$JsArray$foldr, func, acc, values); + } + }); + return A3( + $elm$core$Elm$JsArray$foldr, + helper, + A3($elm$core$Elm$JsArray$foldr, func, baseCase, tail), + tree); + }); +var $elm$core$Array$toList = function (array) { + return A3($elm$core$Array$foldr, $elm$core$List$cons, _List_Nil, array); +}; +var $elm$core$Result$Err = function (a) { + return {$: 'Err', a: a}; +}; +var $elm$json$Json$Decode$Failure = F2( + function (a, b) { + return {$: 'Failure', a: a, b: b}; + }); +var $elm$json$Json$Decode$Field = F2( + function (a, b) { + return {$: 'Field', a: a, b: b}; + }); +var $elm$json$Json$Decode$Index = F2( + function (a, b) { + return {$: 'Index', a: a, b: b}; + }); +var $elm$core$Result$Ok = function (a) { + return {$: 'Ok', a: a}; +}; +var $elm$json$Json$Decode$OneOf = function (a) { + return {$: 'OneOf', a: a}; +}; +var $elm$core$Basics$False = {$: 'False'}; +var $elm$core$Basics$add = _Basics_add; +var $elm$core$Maybe$Just = function (a) { + return {$: 'Just', a: a}; +}; +var $elm$core$Maybe$Nothing = {$: 'Nothing'}; +var $elm$core$String$all = _String_all; +var $elm$core$Basics$and = _Basics_and; +var $elm$core$Basics$append = _Utils_append; +var $elm$json$Json$Encode$encode = _Json_encode; +var $elm$core$String$fromInt = _String_fromNumber; +var $elm$core$String$join = F2( + function (sep, chunks) { + return A2( + _String_join, + sep, + _List_toArray(chunks)); + }); +var $elm$core$String$split = F2( + function (sep, string) { + return _List_fromArray( + A2(_String_split, sep, string)); + }); +var $elm$json$Json$Decode$indent = function (str) { + return A2( + $elm$core$String$join, + '\n ', + A2($elm$core$String$split, '\n', str)); +}; +var $elm$core$List$foldl = F3( + function (func, acc, list) { + foldl: + while (true) { + if (!list.b) { + return acc; + } else { + var x = list.a; + var xs = list.b; + var $temp$func = func, + $temp$acc = A2(func, x, acc), + $temp$list = xs; + func = $temp$func; + acc = $temp$acc; + list = $temp$list; + continue foldl; + } + } + }); +var $elm$core$List$length = function (xs) { + return A3( + $elm$core$List$foldl, + F2( + function (_v0, i) { + return i + 1; + }), + 0, + xs); +}; +var $elm$core$List$map2 = _List_map2; +var $elm$core$Basics$le = _Utils_le; +var $elm$core$Basics$sub = _Basics_sub; +var $elm$core$List$rangeHelp = F3( + function (lo, hi, list) { + rangeHelp: + while (true) { + if (_Utils_cmp(lo, hi) < 1) { + var $temp$lo = lo, + $temp$hi = hi - 1, + $temp$list = A2($elm$core$List$cons, hi, list); + lo = $temp$lo; + hi = $temp$hi; + list = $temp$list; + continue rangeHelp; + } else { + return list; + } + } + }); +var $elm$core$List$range = F2( + function (lo, hi) { + return A3($elm$core$List$rangeHelp, lo, hi, _List_Nil); + }); +var $elm$core$List$indexedMap = F2( + function (f, xs) { + return A3( + $elm$core$List$map2, + f, + A2( + $elm$core$List$range, + 0, + $elm$core$List$length(xs) - 1), + xs); + }); +var $elm$core$Char$toCode = _Char_toCode; +var $elm$core$Char$isLower = function (_char) { + var code = $elm$core$Char$toCode(_char); + return (97 <= code) && (code <= 122); +}; +var $elm$core$Char$isUpper = function (_char) { + var code = $elm$core$Char$toCode(_char); + return (code <= 90) && (65 <= code); +}; +var $elm$core$Basics$or = _Basics_or; +var $elm$core$Char$isAlpha = function (_char) { + return $elm$core$Char$isLower(_char) || $elm$core$Char$isUpper(_char); +}; +var $elm$core$Char$isDigit = function (_char) { + var code = $elm$core$Char$toCode(_char); + return (code <= 57) && (48 <= code); +}; +var $elm$core$Char$isAlphaNum = function (_char) { + return $elm$core$Char$isLower(_char) || ($elm$core$Char$isUpper(_char) || $elm$core$Char$isDigit(_char)); +}; +var $elm$core$List$reverse = function (list) { + return A3($elm$core$List$foldl, $elm$core$List$cons, _List_Nil, list); +}; +var $elm$core$String$uncons = _String_uncons; +var $elm$json$Json$Decode$errorOneOf = F2( + function (i, error) { + return '\n\n(' + ($elm$core$String$fromInt(i + 1) + (') ' + $elm$json$Json$Decode$indent( + $elm$json$Json$Decode$errorToString(error)))); + }); +var $elm$json$Json$Decode$errorToString = function (error) { + return A2($elm$json$Json$Decode$errorToStringHelp, error, _List_Nil); +}; +var $elm$json$Json$Decode$errorToStringHelp = F2( + function (error, context) { + errorToStringHelp: + while (true) { + switch (error.$) { + case 'Field': + var f = error.a; + var err = error.b; + var isSimple = function () { + var _v1 = $elm$core$String$uncons(f); + if (_v1.$ === 'Nothing') { + return false; + } else { + var _v2 = _v1.a; + var _char = _v2.a; + var rest = _v2.b; + return $elm$core$Char$isAlpha(_char) && A2($elm$core$String$all, $elm$core$Char$isAlphaNum, rest); + } + }(); + var fieldName = isSimple ? ('.' + f) : ('[\'' + (f + '\']')); + var $temp$error = err, + $temp$context = A2($elm$core$List$cons, fieldName, context); + error = $temp$error; + context = $temp$context; + continue errorToStringHelp; + case 'Index': + var i = error.a; + var err = error.b; + var indexName = '[' + ($elm$core$String$fromInt(i) + ']'); + var $temp$error = err, + $temp$context = A2($elm$core$List$cons, indexName, context); + error = $temp$error; + context = $temp$context; + continue errorToStringHelp; + case 'OneOf': + var errors = error.a; + if (!errors.b) { + return 'Ran into a Json.Decode.oneOf with no possibilities' + function () { + if (!context.b) { + return '!'; + } else { + return ' at json' + A2( + $elm$core$String$join, + '', + $elm$core$List$reverse(context)); + } + }(); + } else { + if (!errors.b.b) { + var err = errors.a; + var $temp$error = err, + $temp$context = context; + error = $temp$error; + context = $temp$context; + continue errorToStringHelp; + } else { + var starter = function () { + if (!context.b) { + return 'Json.Decode.oneOf'; + } else { + return 'The Json.Decode.oneOf at json' + A2( + $elm$core$String$join, + '', + $elm$core$List$reverse(context)); + } + }(); + var introduction = starter + (' failed in the following ' + ($elm$core$String$fromInt( + $elm$core$List$length(errors)) + ' ways:')); + return A2( + $elm$core$String$join, + '\n\n', + A2( + $elm$core$List$cons, + introduction, + A2($elm$core$List$indexedMap, $elm$json$Json$Decode$errorOneOf, errors))); + } + } + default: + var msg = error.a; + var json = error.b; + var introduction = function () { + if (!context.b) { + return 'Problem with the given value:\n\n'; + } else { + return 'Problem with the value at json' + (A2( + $elm$core$String$join, + '', + $elm$core$List$reverse(context)) + ':\n\n '); + } + }(); + return introduction + ($elm$json$Json$Decode$indent( + A2($elm$json$Json$Encode$encode, 4, json)) + ('\n\n' + msg)); + } + } + }); +var $elm$core$Array$branchFactor = 32; +var $elm$core$Array$Array_elm_builtin = F4( + function (a, b, c, d) { + return {$: 'Array_elm_builtin', a: a, b: b, c: c, d: d}; + }); +var $elm$core$Elm$JsArray$empty = _JsArray_empty; +var $elm$core$Basics$ceiling = _Basics_ceiling; +var $elm$core$Basics$fdiv = _Basics_fdiv; +var $elm$core$Basics$logBase = F2( + function (base, number) { + return _Basics_log(number) / _Basics_log(base); + }); +var $elm$core$Basics$toFloat = _Basics_toFloat; +var $elm$core$Array$shiftStep = $elm$core$Basics$ceiling( + A2($elm$core$Basics$logBase, 2, $elm$core$Array$branchFactor)); +var $elm$core$Array$empty = A4($elm$core$Array$Array_elm_builtin, 0, $elm$core$Array$shiftStep, $elm$core$Elm$JsArray$empty, $elm$core$Elm$JsArray$empty); +var $elm$core$Elm$JsArray$initialize = _JsArray_initialize; +var $elm$core$Array$Leaf = function (a) { + return {$: 'Leaf', a: a}; +}; +var $elm$core$Basics$apL = F2( + function (f, x) { + return f(x); + }); +var $elm$core$Basics$apR = F2( + function (x, f) { + return f(x); + }); +var $elm$core$Basics$eq = _Utils_equal; +var $elm$core$Basics$floor = _Basics_floor; +var $elm$core$Elm$JsArray$length = _JsArray_length; +var $elm$core$Basics$gt = _Utils_gt; +var $elm$core$Basics$max = F2( + function (x, y) { + return (_Utils_cmp(x, y) > 0) ? x : y; + }); +var $elm$core$Basics$mul = _Basics_mul; +var $elm$core$Array$SubTree = function (a) { + return {$: 'SubTree', a: a}; +}; +var $elm$core$Elm$JsArray$initializeFromList = _JsArray_initializeFromList; +var $elm$core$Array$compressNodes = F2( + function (nodes, acc) { + compressNodes: + while (true) { + var _v0 = A2($elm$core$Elm$JsArray$initializeFromList, $elm$core$Array$branchFactor, nodes); + var node = _v0.a; + var remainingNodes = _v0.b; + var newAcc = A2( + $elm$core$List$cons, + $elm$core$Array$SubTree(node), + acc); + if (!remainingNodes.b) { + return $elm$core$List$reverse(newAcc); + } else { + var $temp$nodes = remainingNodes, + $temp$acc = newAcc; + nodes = $temp$nodes; + acc = $temp$acc; + continue compressNodes; + } + } + }); +var $elm$core$Tuple$first = function (_v0) { + var x = _v0.a; + return x; +}; +var $elm$core$Array$treeFromBuilder = F2( + function (nodeList, nodeListSize) { + treeFromBuilder: + while (true) { + var newNodeSize = $elm$core$Basics$ceiling(nodeListSize / $elm$core$Array$branchFactor); + if (newNodeSize === 1) { + return A2($elm$core$Elm$JsArray$initializeFromList, $elm$core$Array$branchFactor, nodeList).a; + } else { + var $temp$nodeList = A2($elm$core$Array$compressNodes, nodeList, _List_Nil), + $temp$nodeListSize = newNodeSize; + nodeList = $temp$nodeList; + nodeListSize = $temp$nodeListSize; + continue treeFromBuilder; + } + } + }); +var $elm$core$Array$builderToArray = F2( + function (reverseNodeList, builder) { + if (!builder.nodeListSize) { + return A4( + $elm$core$Array$Array_elm_builtin, + $elm$core$Elm$JsArray$length(builder.tail), + $elm$core$Array$shiftStep, + $elm$core$Elm$JsArray$empty, + builder.tail); + } else { + var treeLen = builder.nodeListSize * $elm$core$Array$branchFactor; + var depth = $elm$core$Basics$floor( + A2($elm$core$Basics$logBase, $elm$core$Array$branchFactor, treeLen - 1)); + var correctNodeList = reverseNodeList ? $elm$core$List$reverse(builder.nodeList) : builder.nodeList; + var tree = A2($elm$core$Array$treeFromBuilder, correctNodeList, builder.nodeListSize); + return A4( + $elm$core$Array$Array_elm_builtin, + $elm$core$Elm$JsArray$length(builder.tail) + treeLen, + A2($elm$core$Basics$max, 5, depth * $elm$core$Array$shiftStep), + tree, + builder.tail); + } + }); +var $elm$core$Basics$idiv = _Basics_idiv; +var $elm$core$Basics$lt = _Utils_lt; +var $elm$core$Array$initializeHelp = F5( + function (fn, fromIndex, len, nodeList, tail) { + initializeHelp: + while (true) { + if (fromIndex < 0) { + return A2( + $elm$core$Array$builderToArray, + false, + {nodeList: nodeList, nodeListSize: (len / $elm$core$Array$branchFactor) | 0, tail: tail}); + } else { + var leaf = $elm$core$Array$Leaf( + A3($elm$core$Elm$JsArray$initialize, $elm$core$Array$branchFactor, fromIndex, fn)); + var $temp$fn = fn, + $temp$fromIndex = fromIndex - $elm$core$Array$branchFactor, + $temp$len = len, + $temp$nodeList = A2($elm$core$List$cons, leaf, nodeList), + $temp$tail = tail; + fn = $temp$fn; + fromIndex = $temp$fromIndex; + len = $temp$len; + nodeList = $temp$nodeList; + tail = $temp$tail; + continue initializeHelp; + } + } + }); +var $elm$core$Basics$remainderBy = _Basics_remainderBy; +var $elm$core$Array$initialize = F2( + function (len, fn) { + if (len <= 0) { + return $elm$core$Array$empty; + } else { + var tailLen = len % $elm$core$Array$branchFactor; + var tail = A3($elm$core$Elm$JsArray$initialize, tailLen, len - tailLen, fn); + var initialFromIndex = (len - tailLen) - $elm$core$Array$branchFactor; + return A5($elm$core$Array$initializeHelp, fn, initialFromIndex, len, _List_Nil, tail); + } + }); +var $elm$core$Basics$True = {$: 'True'}; +var $elm$core$Result$isOk = function (result) { + if (result.$ === 'Ok') { + return true; + } else { + return false; + } +}; +var $elm$json$Json$Decode$map = _Json_map1; +var $elm$json$Json$Decode$map2 = _Json_map2; +var $elm$json$Json$Decode$succeed = _Json_succeed; +var $elm$virtual_dom$VirtualDom$toHandlerInt = function (handler) { + switch (handler.$) { + case 'Normal': + return 0; + case 'MayStopPropagation': + return 1; + case 'MayPreventDefault': + return 2; + default: + return 3; + } +}; +var $elm$browser$Browser$External = function (a) { + return {$: 'External', a: a}; +}; +var $elm$browser$Browser$Internal = function (a) { + return {$: 'Internal', a: a}; +}; +var $elm$core$Basics$identity = function (x) { + return x; +}; +var $elm$browser$Browser$Dom$NotFound = function (a) { + return {$: 'NotFound', a: a}; +}; +var $elm$url$Url$Http = {$: 'Http'}; +var $elm$url$Url$Https = {$: 'Https'}; +var $elm$url$Url$Url = F6( + function (protocol, host, port_, path, query, fragment) { + return {fragment: fragment, host: host, path: path, port_: port_, protocol: protocol, query: query}; + }); +var $elm$core$String$contains = _String_contains; +var $elm$core$String$length = _String_length; +var $elm$core$String$slice = _String_slice; +var $elm$core$String$dropLeft = F2( + function (n, string) { + return (n < 1) ? string : A3( + $elm$core$String$slice, + n, + $elm$core$String$length(string), + string); + }); +var $elm$core$String$indexes = _String_indexes; +var $elm$core$String$isEmpty = function (string) { + return string === ''; +}; +var $elm$core$String$left = F2( + function (n, string) { + return (n < 1) ? '' : A3($elm$core$String$slice, 0, n, string); + }); +var $elm$core$String$toInt = _String_toInt; +var $elm$url$Url$chompBeforePath = F5( + function (protocol, path, params, frag, str) { + if ($elm$core$String$isEmpty(str) || A2($elm$core$String$contains, '@', str)) { + return $elm$core$Maybe$Nothing; + } else { + var _v0 = A2($elm$core$String$indexes, ':', str); + if (!_v0.b) { + return $elm$core$Maybe$Just( + A6($elm$url$Url$Url, protocol, str, $elm$core$Maybe$Nothing, path, params, frag)); + } else { + if (!_v0.b.b) { + var i = _v0.a; + var _v1 = $elm$core$String$toInt( + A2($elm$core$String$dropLeft, i + 1, str)); + if (_v1.$ === 'Nothing') { + return $elm$core$Maybe$Nothing; + } else { + var port_ = _v1; + return $elm$core$Maybe$Just( + A6( + $elm$url$Url$Url, + protocol, + A2($elm$core$String$left, i, str), + port_, + path, + params, + frag)); + } + } else { + return $elm$core$Maybe$Nothing; + } + } + } + }); +var $elm$url$Url$chompBeforeQuery = F4( + function (protocol, params, frag, str) { + if ($elm$core$String$isEmpty(str)) { + return $elm$core$Maybe$Nothing; + } else { + var _v0 = A2($elm$core$String$indexes, '/', str); + if (!_v0.b) { + return A5($elm$url$Url$chompBeforePath, protocol, '/', params, frag, str); + } else { + var i = _v0.a; + return A5( + $elm$url$Url$chompBeforePath, + protocol, + A2($elm$core$String$dropLeft, i, str), + params, + frag, + A2($elm$core$String$left, i, str)); + } + } + }); +var $elm$url$Url$chompBeforeFragment = F3( + function (protocol, frag, str) { + if ($elm$core$String$isEmpty(str)) { + return $elm$core$Maybe$Nothing; + } else { + var _v0 = A2($elm$core$String$indexes, '?', str); + if (!_v0.b) { + return A4($elm$url$Url$chompBeforeQuery, protocol, $elm$core$Maybe$Nothing, frag, str); + } else { + var i = _v0.a; + return A4( + $elm$url$Url$chompBeforeQuery, + protocol, + $elm$core$Maybe$Just( + A2($elm$core$String$dropLeft, i + 1, str)), + frag, + A2($elm$core$String$left, i, str)); + } + } + }); +var $elm$url$Url$chompAfterProtocol = F2( + function (protocol, str) { + if ($elm$core$String$isEmpty(str)) { + return $elm$core$Maybe$Nothing; + } else { + var _v0 = A2($elm$core$String$indexes, '#', str); + if (!_v0.b) { + return A3($elm$url$Url$chompBeforeFragment, protocol, $elm$core$Maybe$Nothing, str); + } else { + var i = _v0.a; + return A3( + $elm$url$Url$chompBeforeFragment, + protocol, + $elm$core$Maybe$Just( + A2($elm$core$String$dropLeft, i + 1, str)), + A2($elm$core$String$left, i, str)); + } + } + }); +var $elm$core$String$startsWith = _String_startsWith; +var $elm$url$Url$fromString = function (str) { + return A2($elm$core$String$startsWith, 'http://', str) ? A2( + $elm$url$Url$chompAfterProtocol, + $elm$url$Url$Http, + A2($elm$core$String$dropLeft, 7, str)) : (A2($elm$core$String$startsWith, 'https://', str) ? A2( + $elm$url$Url$chompAfterProtocol, + $elm$url$Url$Https, + A2($elm$core$String$dropLeft, 8, str)) : $elm$core$Maybe$Nothing); +}; +var $elm$core$Basics$never = function (_v0) { + never: + while (true) { + var nvr = _v0.a; + var $temp$_v0 = nvr; + _v0 = $temp$_v0; + continue never; + } +}; +var $elm$core$Task$Perform = function (a) { + return {$: 'Perform', a: a}; +}; +var $elm$core$Task$succeed = _Scheduler_succeed; +var $elm$core$Task$init = $elm$core$Task$succeed(_Utils_Tuple0); +var $elm$core$List$foldrHelper = F4( + function (fn, acc, ctr, ls) { + if (!ls.b) { + return acc; + } else { + var a = ls.a; + var r1 = ls.b; + if (!r1.b) { + return A2(fn, a, acc); + } else { + var b = r1.a; + var r2 = r1.b; + if (!r2.b) { + return A2( + fn, + a, + A2(fn, b, acc)); + } else { + var c = r2.a; + var r3 = r2.b; + if (!r3.b) { + return A2( + fn, + a, + A2( + fn, + b, + A2(fn, c, acc))); + } else { + var d = r3.a; + var r4 = r3.b; + var res = (ctr > 500) ? A3( + $elm$core$List$foldl, + fn, + acc, + $elm$core$List$reverse(r4)) : A4($elm$core$List$foldrHelper, fn, acc, ctr + 1, r4); + return A2( + fn, + a, + A2( + fn, + b, + A2( + fn, + c, + A2(fn, d, res)))); + } + } + } + } + }); +var $elm$core$List$foldr = F3( + function (fn, acc, ls) { + return A4($elm$core$List$foldrHelper, fn, acc, 0, ls); + }); +var $elm$core$List$map = F2( + function (f, xs) { + return A3( + $elm$core$List$foldr, + F2( + function (x, acc) { + return A2( + $elm$core$List$cons, + f(x), + acc); + }), + _List_Nil, + xs); + }); +var $elm$core$Task$andThen = _Scheduler_andThen; +var $elm$core$Task$map = F2( + function (func, taskA) { + return A2( + $elm$core$Task$andThen, + function (a) { + return $elm$core$Task$succeed( + func(a)); + }, + taskA); + }); +var $elm$core$Task$map2 = F3( + function (func, taskA, taskB) { + return A2( + $elm$core$Task$andThen, + function (a) { + return A2( + $elm$core$Task$andThen, + function (b) { + return $elm$core$Task$succeed( + A2(func, a, b)); + }, + taskB); + }, + taskA); + }); +var $elm$core$Task$sequence = function (tasks) { + return A3( + $elm$core$List$foldr, + $elm$core$Task$map2($elm$core$List$cons), + $elm$core$Task$succeed(_List_Nil), + tasks); +}; +var $elm$core$Platform$sendToApp = _Platform_sendToApp; +var $elm$core$Task$spawnCmd = F2( + function (router, _v0) { + var task = _v0.a; + return _Scheduler_spawn( + A2( + $elm$core$Task$andThen, + $elm$core$Platform$sendToApp(router), + task)); + }); +var $elm$core$Task$onEffects = F3( + function (router, commands, state) { + return A2( + $elm$core$Task$map, + function (_v0) { + return _Utils_Tuple0; + }, + $elm$core$Task$sequence( + A2( + $elm$core$List$map, + $elm$core$Task$spawnCmd(router), + commands))); + }); +var $elm$core$Task$onSelfMsg = F3( + function (_v0, _v1, _v2) { + return $elm$core$Task$succeed(_Utils_Tuple0); + }); +var $elm$core$Task$cmdMap = F2( + function (tagger, _v0) { + var task = _v0.a; + return $elm$core$Task$Perform( + A2($elm$core$Task$map, tagger, task)); + }); +_Platform_effectManagers['Task'] = _Platform_createManager($elm$core$Task$init, $elm$core$Task$onEffects, $elm$core$Task$onSelfMsg, $elm$core$Task$cmdMap); +var $elm$core$Task$command = _Platform_leaf('Task'); +var $elm$core$Task$perform = F2( + function (toMessage, task) { + return $elm$core$Task$command( + $elm$core$Task$Perform( + A2($elm$core$Task$map, toMessage, task))); + }); +var $elm$browser$Browser$document = _Browser_document; +var $author$project$App$SetMap = function (a) { + return {$: 'SetMap', a: a}; +}; +var $elm$random$Random$Generate = function (a) { + return {$: 'Generate', a: a}; +}; +var $elm$random$Random$Seed = F2( + function (a, b) { + return {$: 'Seed', a: a, b: b}; + }); +var $elm$core$Bitwise$shiftRightZfBy = _Bitwise_shiftRightZfBy; +var $elm$random$Random$next = function (_v0) { + var state0 = _v0.a; + var incr = _v0.b; + return A2($elm$random$Random$Seed, ((state0 * 1664525) + incr) >>> 0, incr); +}; +var $elm$random$Random$initialSeed = function (x) { + var _v0 = $elm$random$Random$next( + A2($elm$random$Random$Seed, 0, 1013904223)); + var state1 = _v0.a; + var incr = _v0.b; + var state2 = (state1 + x) >>> 0; + return $elm$random$Random$next( + A2($elm$random$Random$Seed, state2, incr)); +}; +var $elm$time$Time$Name = function (a) { + return {$: 'Name', a: a}; +}; +var $elm$time$Time$Offset = function (a) { + return {$: 'Offset', a: a}; +}; +var $elm$time$Time$Zone = F2( + function (a, b) { + return {$: 'Zone', a: a, b: b}; + }); +var $elm$time$Time$customZone = $elm$time$Time$Zone; +var $elm$time$Time$Posix = function (a) { + return {$: 'Posix', a: a}; +}; +var $elm$time$Time$millisToPosix = $elm$time$Time$Posix; +var $elm$time$Time$now = _Time_now($elm$time$Time$millisToPosix); +var $elm$time$Time$posixToMillis = function (_v0) { + var millis = _v0.a; + return millis; +}; +var $elm$random$Random$init = A2( + $elm$core$Task$andThen, + function (time) { + return $elm$core$Task$succeed( + $elm$random$Random$initialSeed( + $elm$time$Time$posixToMillis(time))); + }, + $elm$time$Time$now); +var $elm$random$Random$step = F2( + function (_v0, seed) { + var generator = _v0.a; + return generator(seed); + }); +var $elm$random$Random$onEffects = F3( + function (router, commands, seed) { + if (!commands.b) { + return $elm$core$Task$succeed(seed); + } else { + var generator = commands.a.a; + var rest = commands.b; + var _v1 = A2($elm$random$Random$step, generator, seed); + var value = _v1.a; + var newSeed = _v1.b; + return A2( + $elm$core$Task$andThen, + function (_v2) { + return A3($elm$random$Random$onEffects, router, rest, newSeed); + }, + A2($elm$core$Platform$sendToApp, router, value)); + } + }); +var $elm$random$Random$onSelfMsg = F3( + function (_v0, _v1, seed) { + return $elm$core$Task$succeed(seed); + }); +var $elm$random$Random$Generator = function (a) { + return {$: 'Generator', a: a}; +}; +var $elm$random$Random$map = F2( + function (func, _v0) { + var genA = _v0.a; + return $elm$random$Random$Generator( + function (seed0) { + var _v1 = genA(seed0); + var a = _v1.a; + var seed1 = _v1.b; + return _Utils_Tuple2( + func(a), + seed1); + }); + }); +var $elm$random$Random$cmdMap = F2( + function (func, _v0) { + var generator = _v0.a; + return $elm$random$Random$Generate( + A2($elm$random$Random$map, func, generator)); + }); +_Platform_effectManagers['Random'] = _Platform_createManager($elm$random$Random$init, $elm$random$Random$onEffects, $elm$random$Random$onSelfMsg, $elm$random$Random$cmdMap); +var $elm$random$Random$command = _Platform_leaf('Random'); +var $elm$random$Random$generate = F2( + function (tagger, generator) { + return $elm$random$Random$command( + $elm$random$Random$Generate( + A2($elm$random$Random$map, tagger, generator))); + }); +var $author$project$App$BlankClick = {$: 'BlankClick'}; +var $author$project$App$RoadTool = {$: 'RoadTool'}; +var $author$project$App$blank_map = {obstacles: _List_Nil, roads: _List_Nil, towns: _List_Nil}; +var $author$project$App$init_camera = { + pan: _Utils_Tuple2(0, 0), + zoom: 1 +}; +var $author$project$App$init_model = { + camera: $author$project$App$init_camera, + click_mode: $author$project$App$BlankClick, + debug_log: _List_Nil, + map: $author$project$App$blank_map, + pointer: _Utils_Tuple2(0, 0), + selected_town: $elm$core$Maybe$Nothing, + tool: $author$project$App$RoadTool +}; +var $elm$random$Random$andThen = F2( + function (callback, _v0) { + var genA = _v0.a; + return $elm$random$Random$Generator( + function (seed) { + var _v1 = genA(seed); + var result = _v1.a; + var newSeed = _v1.b; + var _v2 = callback(result); + var genB = _v2.a; + return genB(newSeed); + }); + }); +var $elm$core$Basics$composeR = F3( + function (f, g, x) { + return g( + f(x)); + }); +var $elm$random$Random$constant = function (value) { + return $elm$random$Random$Generator( + function (seed) { + return _Utils_Tuple2(value, seed); + }); +}; +var $elm$core$Basics$sqrt = _Basics_sqrt; +var $author$project$Vector$len = function (_v0) { + var x = _v0.a; + var y = _v0.b; + return $elm$core$Basics$sqrt((x * x) + (y * y)); +}; +var $author$project$Vector$sub = F2( + function (_v0, _v1) { + var x1 = _v0.a; + var y1 = _v0.b; + var x2 = _v1.a; + var y2 = _v1.b; + return _Utils_Tuple2(x1 - x2, y1 - y2); + }); +var $author$project$Vector$distance = F2( + function (v1, v2) { + return $author$project$Vector$len( + A2($author$project$Vector$sub, v1, v2)); + }); +var $author$project$Vector$add = F2( + function (_v0, _v1) { + var x1 = _v0.a; + var y1 = _v0.b; + var x2 = _v1.a; + var y2 = _v1.b; + return _Utils_Tuple2(x1 + x2, y1 + y2); + }); +var $elm$core$List$filter = F2( + function (isGood, list) { + return A3( + $elm$core$List$foldr, + F2( + function (x, xs) { + return isGood(x) ? A2($elm$core$List$cons, x, xs) : xs; + }), + _List_Nil, + list); + }); +var $elm$core$Basics$neq = _Utils_notEqual; +var $author$project$Vector$normalise = function (_v0) { + var x = _v0.a; + var y = _v0.b; + var d = $author$project$Vector$len( + _Utils_Tuple2(x, y)); + return _Utils_Tuple2(x / d, y / d); +}; +var $author$project$Vector$smul = F2( + function (s, _v0) { + var x = _v0.a; + var y = _v0.b; + return _Utils_Tuple2(s * x, s * y); + }); +var $author$project$Vector$sum = A2( + $elm$core$List$foldl, + $author$project$Vector$add, + _Utils_Tuple2(0, 0)); +var $author$project$App$distribute_dots = F2( + function (min_dist, dots) { + var force_for_dot = function (dot) { + var r1 = dot.radius; + var p1 = dot.position; + var dot_forces = A2( + $elm$core$List$map, + function (d2) { + var r2 = d2.radius; + var p2 = d2.position; + var v = A2($author$project$Vector$sub, p2, p1); + var n = $author$project$Vector$normalise(v); + var d = $author$project$Vector$len(v) - ((min_dist + r1) + r2); + var force_strength = (d < 0) ? 0.1 : 0; + return A2($author$project$Vector$smul, d * force_strength, n); + }, + A2( + $elm$core$List$filter, + $elm$core$Basics$neq(dot), + dots)); + return $author$project$Vector$sum(dot_forces); + }; + var forces = A2($elm$core$List$map, force_for_dot, dots); + return A3( + $elm$core$List$map2, + F2( + function (d, f) { + return A2($author$project$Vector$add, d.position, f); + }), + dots, + forces); + }); +var $author$project$App$iterate_until = F4( + function (run, fn, condition, list) { + iterate_until: + while (true) { + var nlist = fn(list); + if (A2(condition, list, nlist)) { + return nlist; + } else { + var $temp$run = run + 1, + $temp$fn = fn, + $temp$condition = condition, + $temp$list = nlist; + run = $temp$run; + fn = $temp$fn; + condition = $temp$condition; + list = $temp$list; + continue iterate_until; + } + } + }); +var $elm$core$List$sum = function (numbers) { + return A3($elm$core$List$foldl, $elm$core$Basics$add, 0, numbers); +}; +var $author$project$App$distribute_towns = F2( + function (obstacles, original_towns) { + var stopped_moving = F2( + function (otowns, ntowns) { + return 1 > $elm$core$List$sum( + A3( + $elm$core$List$map2, + F2( + function (t1, t2) { + return A2($author$project$Vector$distance, t1.position, t2.position); + }), + otowns, + ntowns)); + }); + var step = function (towns) { + var town_obstacles = A2( + $elm$core$List$map, + function (t) { + return {position: t.position, radius: 1}; + }, + towns); + var positions = A2( + $author$project$App$distribute_dots, + 5, + _Utils_ap(town_obstacles, obstacles)); + return A3( + $elm$core$List$map2, + F2( + function (t, p) { + return _Utils_update( + t, + {position: p}); + }), + towns, + positions); + }; + return A4($author$project$App$iterate_until, 0, step, stopped_moving, original_towns); + }); +var $elm$core$Basics$negate = function (n) { + return -n; +}; +var $elm$core$Basics$abs = function (n) { + return (n < 0) ? (-n) : n; +}; +var $elm$core$Bitwise$and = _Bitwise_and; +var $elm$core$Bitwise$xor = _Bitwise_xor; +var $elm$random$Random$peel = function (_v0) { + var state = _v0.a; + var word = (state ^ (state >>> ((state >>> 28) + 4))) * 277803737; + return ((word >>> 22) ^ word) >>> 0; +}; +var $elm$random$Random$float = F2( + function (a, b) { + return $elm$random$Random$Generator( + function (seed0) { + var seed1 = $elm$random$Random$next(seed0); + var range = $elm$core$Basics$abs(b - a); + var n1 = $elm$random$Random$peel(seed1); + var n0 = $elm$random$Random$peel(seed0); + var lo = (134217727 & n1) * 1.0; + var hi = (67108863 & n0) * 1.0; + var val = ((hi * 134217728.0) + lo) / 9007199254740992.0; + var scaled = (val * range) + a; + return _Utils_Tuple2( + scaled, + $elm$random$Random$next(seed1)); + }); + }); +var $elm$random$Random$listHelp = F4( + function (revList, n, gen, seed) { + listHelp: + while (true) { + if (n < 1) { + return _Utils_Tuple2(revList, seed); + } else { + var _v0 = gen(seed); + var value = _v0.a; + var newSeed = _v0.b; + var $temp$revList = A2($elm$core$List$cons, value, revList), + $temp$n = n - 1, + $temp$gen = gen, + $temp$seed = newSeed; + revList = $temp$revList; + n = $temp$n; + gen = $temp$gen; + seed = $temp$seed; + continue listHelp; + } + } + }); +var $elm$random$Random$list = F2( + function (n, _v0) { + var gen = _v0.a; + return $elm$random$Random$Generator( + function (seed) { + return A4($elm$random$Random$listHelp, _List_Nil, n, gen, seed); + }); + }); +var $elm$random$Random$map2 = F3( + function (func, _v0, _v1) { + var genA = _v0.a; + var genB = _v1.a; + return $elm$random$Random$Generator( + function (seed0) { + var _v2 = genA(seed0); + var a = _v2.a; + var seed1 = _v2.b; + var _v3 = genB(seed1); + var b = _v3.a; + var seed2 = _v3.b; + return _Utils_Tuple2( + A2(func, a, b), + seed2); + }); + }); +var $elm$core$Tuple$pair = F2( + function (a, b) { + return _Utils_Tuple2(a, b); + }); +var $elm$core$Basics$pow = _Basics_pow; +var $elm$random$Random$addOne = function (value) { + return _Utils_Tuple2(1, value); +}; +var $elm$random$Random$getByWeight = F3( + function (_v0, others, countdown) { + getByWeight: + while (true) { + var weight = _v0.a; + var value = _v0.b; + if (!others.b) { + return value; + } else { + var second = others.a; + var otherOthers = others.b; + if (_Utils_cmp( + countdown, + $elm$core$Basics$abs(weight)) < 1) { + return value; + } else { + var $temp$_v0 = second, + $temp$others = otherOthers, + $temp$countdown = countdown - $elm$core$Basics$abs(weight); + _v0 = $temp$_v0; + others = $temp$others; + countdown = $temp$countdown; + continue getByWeight; + } + } + } + }); +var $elm$random$Random$weighted = F2( + function (first, others) { + var normalize = function (_v0) { + var weight = _v0.a; + return $elm$core$Basics$abs(weight); + }; + var total = normalize(first) + $elm$core$List$sum( + A2($elm$core$List$map, normalize, others)); + return A2( + $elm$random$Random$map, + A2($elm$random$Random$getByWeight, first, others), + A2($elm$random$Random$float, 0, total)); + }); +var $elm$random$Random$uniform = F2( + function (value, valueList) { + return A2( + $elm$random$Random$weighted, + $elm$random$Random$addOne(value), + A2($elm$core$List$map, $elm$random$Random$addOne, valueList)); + }); +var $author$project$App$easy_uniform = F2( + function (never, options) { + if (!options.b) { + return $elm$random$Random$constant(never); + } else { + var a = options.a; + var rest = options.b; + return A2($elm$random$Random$uniform, a, rest); + } + }); +var $author$project$App$random_name = function () { + var vowels = _List_fromArray( + ['a', 'e', 'i', 'o', 'u']); + var uniform_string = $author$project$App$easy_uniform(''); + var consonants = _List_fromArray( + ['b', 'c', 'd', 'g', 'm', 'n', 'p', 'r', 's', 't', 'ch', 'th', 'sh']); + var random_syllable = A3( + $elm$random$Random$map2, + $elm$core$Basics$append, + uniform_string(consonants), + uniform_string(vowels)); + return A2( + $elm$random$Random$map, + $elm$core$String$join(''), + A2($elm$random$Random$list, 3, random_syllable)); +}(); +var $elm$core$Basics$always = F2( + function (a, _v0) { + return a; + }); +var $elm_community$list_extra$List$Extra$updateIf = F3( + function (predicate, update, list) { + return A2( + $elm$core$List$map, + function (item) { + return predicate(item) ? update(item) : item; + }, + list); + }); +var $elm_community$list_extra$List$Extra$setIf = F3( + function (predicate, replacement, list) { + return A3( + $elm_community$list_extra$List$Extra$updateIf, + predicate, + $elm$core$Basics$always(replacement), + list); + }); +var $author$project$App$map_generator = function () { + var random_position = A3( + $elm$random$Random$map2, + $elm$core$Tuple$pair, + A2($elm$random$Random$float, -20, 20), + A2($elm$random$Random$float, -20, 20)); + var random_town = A3( + $elm$random$Random$map2, + F2( + function (p, name) { + return { + buildings: _List_fromArray( + ['⛺']), + id: 0, + items: _List_Nil, + name: name, + position: p + }; + }), + random_position, + $author$project$App$random_name); + var random_obstacle = A3( + $elm$random$Random$map2, + F2( + function (p, size) { + return {position: p, radius: size}; + }), + random_position, + A2( + $elm$random$Random$map, + $elm$core$Basics$sqrt, + A2( + $elm$random$Random$float, + A2($elm$core$Basics$pow, 2, 2), + A2($elm$core$Basics$pow, 6, 2)))); + var generate_towns = function (map) { + return A2( + $elm$random$Random$map, + function (t) { + return _Utils_update( + map, + {towns: t}); + }, + A2( + $elm$random$Random$map, + $author$project$App$distribute_towns(map.obstacles), + A2( + $elm$random$Random$map, + $elm$core$List$indexedMap( + F2( + function (i, t) { + return _Utils_update( + t, + {id: i}); + })), + A2($elm$random$Random$list, 10, random_town)))); + }; + var generate_obstacles = function (map) { + return A2( + $elm$random$Random$map, + function (o) { + return _Utils_update( + map, + {obstacles: o}); + }, + A2($elm$random$Random$list, 20, random_obstacle)); + }; + var add_to_random_town = F2( + function (kind, map) { + var _v0 = map.towns; + if (!_v0.b) { + return $elm$random$Random$constant(map); + } else { + var t1 = _v0.a; + var tothers = _v0.b; + var rtown = A2($elm$random$Random$uniform, t1, tothers); + return A2( + $elm$random$Random$map, + function (town) { + return _Utils_update( + map, + { + towns: A3( + $elm_community$list_extra$List$Extra$setIf, + A2( + $elm$core$Basics$composeR, + function ($) { + return $.id; + }, + $elm$core$Basics$eq(town.id)), + _Utils_update( + town, + { + items: A2( + $elm$core$List$cons, + {kind: kind, town: town.id}, + town.items) + }), + map.towns) + }); + }, + rtown); + } + }); + return A2( + $elm$random$Random$andThen, + add_to_random_town('🌲'), + A2( + $elm$random$Random$andThen, + add_to_random_town('🧍'), + A2( + $elm$random$Random$andThen, + generate_towns, + A2( + $elm$random$Random$andThen, + generate_obstacles, + $elm$random$Random$constant($author$project$App$blank_map))))); +}(); +var $author$project$App$init = function (_v0) { + return _Utils_Tuple2( + $author$project$App$init_model, + A2($elm$random$Random$generate, $author$project$App$SetMap, $author$project$App$map_generator)); +}; +var $elm$core$Platform$Sub$batch = _Platform_batch; +var $elm$core$Platform$Sub$none = $elm$core$Platform$Sub$batch(_List_Nil); +var $author$project$App$subscriptions = function (model) { + return $elm$core$Platform$Sub$none; +}; +var $author$project$App$DragItem = F3( + function (a, b, c) { + return {$: 'DragItem', a: a, b: b, c: c}; + }); +var $author$project$App$DragRoad = F2( + function (a, b) { + return {$: 'DragRoad', a: a, b: b}; + }); +var $author$project$App$PanCamera = function (a) { + return {$: 'PanCamera', a: a}; +}; +var $author$project$App$PointerDown = {$: 'PointerDown'}; +var $author$project$App$PointerUp = {$: 'PointerUp'}; +var $author$project$App$TouchStart = function (a) { + return {$: 'TouchStart', a: a}; +}; +var $elm$core$List$any = F2( + function (isOkay, list) { + any: + while (true) { + if (!list.b) { + return false; + } else { + var x = list.a; + var xs = list.b; + if (isOkay(x)) { + return true; + } else { + var $temp$isOkay = isOkay, + $temp$list = xs; + isOkay = $temp$isOkay; + list = $temp$list; + continue any; + } + } + } + }); +var $elm$core$Basics$composeL = F3( + function (g, f, x) { + return g( + f(x)); + }); +var $elm$core$Basics$not = _Basics_not; +var $elm$core$List$all = F2( + function (isOkay, list) { + return !A2( + $elm$core$List$any, + A2($elm$core$Basics$composeL, $elm$core$Basics$not, isOkay), + list); + }); +var $author$project$App$has_enough = F3( + function (kind, count, list) { + return _Utils_cmp( + count, + $elm$core$List$length( + A2( + $elm$core$List$filter, + $elm$core$Basics$eq(kind), + list))) < 1; + }); +var $author$project$App$has_enough_buildings = F2( + function (kind, count) { + return A2( + $elm$core$Basics$composeR, + function ($) { + return $.buildings; + }, + A2($author$project$App$has_enough, kind, count)); + }); +var $author$project$App$has_enough_items = F2( + function (kind, count) { + return A2( + $elm$core$Basics$composeR, + function ($) { + return $.items; + }, + A2( + $elm$core$Basics$composeR, + $elm$core$List$map( + function ($) { + return $.kind; + }), + A2($author$project$App$has_enough, kind, count))); + }); +var $author$project$App$can_afford_recipe = F2( + function (town, recipe) { + var enough_items = A2( + $elm$core$List$all, + function (_v1) { + var b = _v1.a; + var c = _v1.b; + return A3($author$project$App$has_enough_items, b, c, town); + }, + recipe.in_items); + var enough_buildings = A2( + $elm$core$List$all, + function (_v0) { + var b = _v0.a; + var c = _v0.b; + return A3($author$project$App$has_enough_buildings, b, c, town); + }, + recipe.in_buildings); + return enough_items && enough_buildings; + }); +var $elm$core$List$append = F2( + function (xs, ys) { + if (!ys.b) { + return xs; + } else { + return A3($elm$core$List$foldr, $elm$core$List$cons, ys, xs); + } + }); +var $elm$core$List$concat = function (lists) { + return A3($elm$core$List$foldr, $elm$core$List$append, _List_Nil, lists); +}; +var $elm$core$List$concatMap = F2( + function (f, list) { + return $elm$core$List$concat( + A2($elm$core$List$map, f, list)); + }); +var $elm$core$List$drop = F2( + function (n, list) { + drop: + while (true) { + if (n <= 0) { + return list; + } else { + if (!list.b) { + return list; + } else { + var x = list.a; + var xs = list.b; + var $temp$n = n - 1, + $temp$list = xs; + n = $temp$n; + list = $temp$list; + continue drop; + } + } + } + }); +var $elm$core$List$head = function (list) { + if (list.b) { + var x = list.a; + var xs = list.b; + return $elm$core$Maybe$Just(x); + } else { + return $elm$core$Maybe$Nothing; + } +}; +var $elm_community$list_extra$List$Extra$getAt = F2( + function (idx, xs) { + return (idx < 0) ? $elm$core$Maybe$Nothing : $elm$core$List$head( + A2($elm$core$List$drop, idx, xs)); + }); +var $author$project$App$get_town = F2( + function (model, i) { + return A2($elm_community$list_extra$List$Extra$getAt, i, model.map.towns); + }); +var $elm$core$Maybe$map = F2( + function (f, maybe) { + if (maybe.$ === 'Just') { + var value = maybe.a; + return $elm$core$Maybe$Just( + f(value)); + } else { + return $elm$core$Maybe$Nothing; + } + }); +var $elm$core$List$repeatHelp = F3( + function (result, n, value) { + repeatHelp: + while (true) { + if (n <= 0) { + return result; + } else { + var $temp$result = A2($elm$core$List$cons, value, result), + $temp$n = n - 1, + $temp$value = value; + result = $temp$result; + n = $temp$n; + value = $temp$value; + continue repeatHelp; + } + } + }); +var $elm$core$List$repeat = F2( + function (n, value) { + return A3($elm$core$List$repeatHelp, _List_Nil, n, value); + }); +var $elm$core$Tuple$second = function (_v0) { + var y = _v0.b; + return y; +}; +var $author$project$App$update_map = F2( + function (fn, model) { + return _Utils_update( + model, + { + map: fn(model.map) + }); + }); +var $author$project$App$update_town = F2( + function (fn, townid) { + return $author$project$App$update_map( + function (map) { + return _Utils_update( + map, + { + towns: A3( + $elm_community$list_extra$List$Extra$updateIf, + A2( + $elm$core$Basics$composeR, + function ($) { + return $.id; + }, + $elm$core$Basics$eq(townid)), + fn, + map.towns) + }); + }); + }); +var $author$project$App$spend_buildings = F2( + function (kind, num) { + return $author$project$App$update_town( + function (town) { + return _Utils_update( + town, + { + buildings: A3( + $elm$core$List$foldl, + F2( + function (building, _v0) { + var n = _v0.a; + var o = _v0.b; + return (_Utils_eq(building, kind) && (n > 0)) ? _Utils_Tuple2(n - 1, o) : _Utils_Tuple2( + n, + A2($elm$core$List$cons, building, o)); + }), + _Utils_Tuple2(num, _List_Nil), + town.buildings).b + }); + }); + }); +var $elm$core$Debug$log = _Debug_log; +var $author$project$App$spend_items = F2( + function (kind, num) { + var q = A2( + $elm$core$Debug$log, + 'spend', + _Utils_Tuple2(kind, num)); + return $author$project$App$update_town( + function (town) { + return _Utils_update( + town, + { + items: A3( + $elm$core$List$foldl, + F2( + function (item, _v0) { + var n = _v0.a; + var o = _v0.b; + return (_Utils_eq(item.kind, kind) && (n > 0)) ? _Utils_Tuple2(n - 1, o) : _Utils_Tuple2( + n, + A2($elm$core$List$cons, item, o)); + }), + _Utils_Tuple2(num, _List_Nil), + town.items).b + }); + }); + }); +var $elm$core$Maybe$withDefault = F2( + function (_default, maybe) { + if (maybe.$ === 'Just') { + var value = maybe.a; + return value; + } else { + return _default; + } + }); +var $author$project$App$apply_recipe = F3( + function (townid, recipe, model) { + var _v0 = A2($author$project$App$get_town, model, townid); + if (_v0.$ === 'Nothing') { + return model; + } else { + var town = _v0.a; + var spent_items = function (m) { + return A3( + $elm$core$List$foldl, + F2( + function (_v4, items) { + var b = _v4.a; + var c = _v4.b; + return A4($author$project$App$spend_items, b, c, townid, items); + }), + m, + recipe.in_items); + }; + var spent_buildings = function (m) { + return A3( + $elm$core$List$foldl, + F2( + function (_v3, buildings) { + var b = _v3.a; + var c = _v3.b; + return A4($author$project$App$spend_buildings, b, c, townid, buildings); + }), + m, + recipe.in_buildings); + }; + var new_items = A2( + $elm$core$List$concatMap, + function (_v2) { + var b = _v2.a; + var c = _v2.b; + return A2( + $elm$core$List$repeat, + c, + {kind: b, town: townid}); + }, + recipe.out_items); + var new_buildings = A2( + $elm$core$List$concatMap, + function (_v1) { + var b = _v1.a; + var c = _v1.b; + return A2($elm$core$List$repeat, c, b); + }, + recipe.out_buildings); + var spent_model = A3( + $author$project$App$update_town, + function (t) { + return _Utils_update( + t, + { + buildings: _Utils_ap(new_buildings, t.buildings), + items: _Utils_ap(new_items, t.items) + }); + }, + townid, + spent_items( + spent_buildings(model))); + var max_items = 500; + var final_items = A2( + $elm$core$Maybe$withDefault, + 0, + A2( + $elm$core$Maybe$map, + A2( + $elm$core$Basics$composeR, + function ($) { + return $.items; + }, + $elm$core$List$length), + A2($author$project$App$get_town, spent_model, townid))); + var can_afford = A2($author$project$App$can_afford_recipe, town, recipe); + return (can_afford && (_Utils_cmp(final_items, max_items) < 1)) ? spent_model : model; + } + }); +var $author$project$App$debug = F2( + function (msg, model) { + return _Utils_update( + model, + { + debug_log: A2($elm$core$List$cons, msg, model.debug_log) + }); + }); +var $elm$json$Json$Decode$decodeValue = _Json_run; +var $elm$json$Json$Decode$field = _Json_decodeField; +var $elm$json$Json$Decode$at = F2( + function (fields, decoder) { + return A3($elm$core$List$foldr, $elm$json$Json$Decode$field, decoder, fields); + }); +var $elm$json$Json$Decode$float = _Json_decodeFloat; +var $author$project$App$decode_vector = A3( + $elm$json$Json$Decode$map2, + $elm$core$Tuple$pair, + A2($elm$json$Json$Decode$field, 'x', $elm$json$Json$Decode$float), + A2($elm$json$Json$Decode$field, 'y', $elm$json$Json$Decode$float)); +var $author$project$App$decode_touch_vector = function (fn) { + return A2( + $elm$json$Json$Decode$map, + fn, + A2( + $elm$json$Json$Decode$at, + _List_fromArray( + ['detail', '0', 'position']), + $author$project$App$decode_vector)); +}; +var $author$project$App$Road = F3( + function (a, b, c) { + return {$: 'Road', a: a, b: b, c: c}; + }); +var $elm$core$Result$andThen = F2( + function (callback, result) { + if (result.$ === 'Ok') { + var value = result.a; + return callback(value); + } else { + var msg = result.a; + return $elm$core$Result$Err(msg); + } + }); +var $elm$core$List$sortBy = _List_sortBy; +var $author$project$Vector$closest = F2( + function (get_position, p1) { + return A2( + $elm$core$Basics$composeR, + $elm$core$List$map( + function (a) { + return _Utils_Tuple2( + a, + $author$project$Vector$len( + A2( + $author$project$Vector$sub, + p1, + get_position(a)))); + }), + A2( + $elm$core$Basics$composeR, + $elm$core$List$indexedMap( + F2( + function (i, _v0) { + var a = _v0.a; + var d = _v0.b; + return _Utils_Tuple3(i, d, a); + })), + A2( + $elm$core$Basics$composeR, + $elm$core$List$sortBy( + function (_v1) { + var i = _v1.a; + var d = _v1.b; + var a = _v1.c; + return d; + }), + $elm$core$List$head))); + }); +var $elm$core$Maybe$andThen = F2( + function (callback, maybeValue) { + if (maybeValue.$ === 'Just') { + var value = maybeValue.a; + return callback(value); + } else { + return $elm$core$Maybe$Nothing; + } + }); +var $author$project$Util$maybeIf = function (condition) { + return $elm$core$Maybe$andThen( + function (a) { + return condition(a) ? $elm$core$Maybe$Just(a) : $elm$core$Maybe$Nothing; + }); +}; +var $author$project$Vector$closest_within = F4( + function (get_limit, get_position, p1, things) { + return A2( + $author$project$Util$maybeIf, + function (_v0) { + var i = _v0.a; + var d = _v0.b; + var a = _v0.c; + return _Utils_cmp( + d, + get_limit(a)) < 0; + }, + A3($author$project$Vector$closest, get_position, p1, things)); + }); +var $author$project$App$projected_pointer = function (model) { + return A2( + $author$project$Vector$smul, + model.camera.zoom, + A2($author$project$Vector$sub, model.pointer, model.camera.pan)); +}; +var $author$project$App$select_town = function (model) { + return A4( + $author$project$Vector$closest_within, + function (t) { + return 2; + }, + function ($) { + return $.position; + }, + $author$project$App$projected_pointer(model), + model.map.towns); +}; +var $author$project$Util$third = function (_v0) { + var a = _v0.a; + var b = _v0.b; + var c = _v0.c; + return c; +}; +var $author$project$App$change_selected_town = function (model) { + return _Utils_update( + model, + { + selected_town: A2( + $elm$core$Maybe$map, + A2( + $elm$core$Basics$composeR, + $author$project$Util$third, + function ($) { + return $.id; + }), + $author$project$App$select_town(model)) + }); +}; +var $elm$core$Basics$ge = _Utils_ge; +var $author$project$App$total_length = function (points) { + return $elm$core$List$sum( + A3( + $elm$core$List$map2, + F2( + function (v1, v2) { + return A2($author$project$Vector$distance, v1, v2); + }), + points, + A2($elm$core$List$drop, 1, points))); +}; +var $author$project$App$road_cost = A2( + $elm$core$Basics$composeR, + $author$project$App$total_length, + A2( + $elm$core$Basics$composeR, + $elm$core$Basics$mul(0.2), + $elm$core$Basics$ceiling)); +var $author$project$Util$tf = $elm$core$Basics$toFloat; +var $author$project$App$fract = function (x) { + return _Utils_Tuple2( + $elm$core$Basics$floor(x), + x - $author$project$Util$tf( + $elm$core$Basics$floor(x))); +}; +var $author$project$App$simplify_path = F2( + function (step, points) { + var simplify_middle = F2( + function (p, _v5) { + var last = _v5.a; + var r = _v5.b; + var opoints = _v5.c; + var v = A2($author$project$Vector$sub, p, last); + var n = $author$project$Vector$normalise(v); + var d = $author$project$Vector$len(v); + var _v4 = $author$project$App$fract((r + d) / step); + var steps = _v4.a; + var nr = _v4.b; + var nopoints = A2( + $elm$core$List$map, + function (k) { + return A2( + $author$project$Vector$add, + last, + A2( + $author$project$Vector$smul, + ($author$project$Util$tf(k) - r) * step, + n)); + }, + A2($elm$core$List$range, 1, steps)); + return _Utils_Tuple3( + p, + nr, + _Utils_ap(opoints, nopoints)); + }); + var _v0 = _Utils_Tuple2( + points, + $elm$core$List$reverse(points)); + if (_v0.a.b && _v0.b.b) { + var _v1 = _v0.a; + var start = _v1.a; + var rest = _v1.b; + var _v2 = _v0.b; + var end = _v2.a; + return A2( + $elm$core$List$cons, + start, + _Utils_ap( + function (_v3) { + var opoints = _v3.c; + return opoints; + }( + A3( + $elm$core$List$foldl, + simplify_middle, + _Utils_Tuple3(start, 0, _List_Nil), + points)), + _List_fromArray( + [end]))); + } else { + return _List_Nil; + } + }); +var $author$project$App$simplify_road = $author$project$App$simplify_path(1); +var $author$project$App$stock_of_item = function (kind) { + return A2( + $elm$core$Basics$composeR, + function ($) { + return $.items; + }, + A2( + $elm$core$Basics$composeR, + $elm$core$List$filter( + A2( + $elm$core$Basics$composeR, + function ($) { + return $.kind; + }, + $elm$core$Basics$eq(kind))), + $elm$core$List$length)); +}; +var $elm$core$Debug$toString = _Debug_toString; +var $elm$core$List$takeReverse = F3( + function (n, list, kept) { + takeReverse: + while (true) { + if (n <= 0) { + return kept; + } else { + if (!list.b) { + return kept; + } else { + var x = list.a; + var xs = list.b; + var $temp$n = n - 1, + $temp$list = xs, + $temp$kept = A2($elm$core$List$cons, x, kept); + n = $temp$n; + list = $temp$list; + kept = $temp$kept; + continue takeReverse; + } + } + } + }); +var $elm$core$List$takeTailRec = F2( + function (n, list) { + return $elm$core$List$reverse( + A3($elm$core$List$takeReverse, n, list, _List_Nil)); + }); +var $elm$core$List$takeFast = F3( + function (ctr, n, list) { + if (n <= 0) { + return _List_Nil; + } else { + var _v0 = _Utils_Tuple2(n, list); + _v0$1: + while (true) { + _v0$5: + while (true) { + if (!_v0.b.b) { + return list; + } else { + if (_v0.b.b.b) { + switch (_v0.a) { + case 1: + break _v0$1; + case 2: + var _v2 = _v0.b; + var x = _v2.a; + var _v3 = _v2.b; + var y = _v3.a; + return _List_fromArray( + [x, y]); + case 3: + if (_v0.b.b.b.b) { + var _v4 = _v0.b; + var x = _v4.a; + var _v5 = _v4.b; + var y = _v5.a; + var _v6 = _v5.b; + var z = _v6.a; + return _List_fromArray( + [x, y, z]); + } else { + break _v0$5; + } + default: + if (_v0.b.b.b.b && _v0.b.b.b.b.b) { + var _v7 = _v0.b; + var x = _v7.a; + var _v8 = _v7.b; + var y = _v8.a; + var _v9 = _v8.b; + var z = _v9.a; + var _v10 = _v9.b; + var w = _v10.a; + var tl = _v10.b; + return (ctr > 1000) ? A2( + $elm$core$List$cons, + x, + A2( + $elm$core$List$cons, + y, + A2( + $elm$core$List$cons, + z, + A2( + $elm$core$List$cons, + w, + A2($elm$core$List$takeTailRec, n - 4, tl))))) : A2( + $elm$core$List$cons, + x, + A2( + $elm$core$List$cons, + y, + A2( + $elm$core$List$cons, + z, + A2( + $elm$core$List$cons, + w, + A3($elm$core$List$takeFast, ctr + 1, n - 4, tl))))); + } else { + break _v0$5; + } + } + } else { + if (_v0.a === 1) { + break _v0$1; + } else { + break _v0$5; + } + } + } + } + return list; + } + var _v1 = _v0.b; + var x = _v1.a; + return _List_fromArray( + [x]); + } + }); +var $elm$core$List$take = F2( + function (n, list) { + return A3($elm$core$List$takeFast, 0, n, list); + }); +var $elm_community$list_extra$List$Extra$updateAt = F3( + function (index, fn, list) { + if (index < 0) { + return list; + } else { + var tail = A2($elm$core$List$drop, index, list); + if (tail.b) { + var x = tail.a; + var xs = tail.b; + return _Utils_ap( + A2($elm$core$List$take, index, list), + A2( + $elm$core$List$cons, + fn(x), + xs)); + } else { + return list; + } + } + }); +var $author$project$App$path_intersects_obstacle = F2( + function (path, obstacle) { + return A2( + $elm$core$List$any, + A2( + $elm$core$Basics$composeR, + $author$project$Vector$distance(obstacle.position), + $elm$core$Basics$gt(obstacle.radius)), + path); + }); +var $author$project$App$valid_road = F2( + function (model, path) { + var map = model.map; + var hit_obstacles = A2( + $elm$core$List$filter, + $author$project$App$path_intersects_obstacle(path), + map.obstacles); + return _Utils_eq(hit_obstacles, _List_Nil); + }); +var $author$project$App$end_touch = function (model) { + var _v0 = A2($elm$core$Debug$log, 'end_touch', model.click_mode); + switch (_v0.$) { + case 'BlankClick': + return $author$project$App$change_selected_town(model); + case 'DragRoad': + var id1 = _v0.a; + var path = _v0.b; + var road = function () { + var _v4 = $author$project$App$select_town(model); + if (_v4.$ === 'Nothing') { + return $elm$core$Result$Err('no town'); + } else { + var _v5 = _v4.a; + var j = _v5.a; + var d = _v5.b; + var t = _v5.c; + return _Utils_eq(id1, t.id) ? $elm$core$Result$Err('same start and end') : $elm$core$Result$Ok( + A3( + $author$project$App$Road, + id1, + t.id, + $author$project$App$simplify_road( + A2($elm$core$List$cons, t.position, path)))); + } + }(); + var is_valid = function (rroad) { + var rpath = rroad.c; + return A2($author$project$App$valid_road, model, rpath) ? $elm$core$Result$Ok(rroad) : $elm$core$Result$Err('hits an obstacle'); + }; + var cost = $author$project$App$road_cost(path); + var can_afford = function (rroad) { + var from = rroad.a; + var to = rroad.b; + var rocks_from = A2( + $elm$core$Maybe$withDefault, + 0, + A2( + $elm$core$Maybe$map, + $author$project$App$stock_of_item('🪨'), + A2($author$project$App$get_town, model, from))); + return (_Utils_cmp(rocks_from, cost) > -1) ? $elm$core$Result$Ok(rroad) : $elm$core$Result$Err('Not enough 🪨'); + }; + var result = A2( + $elm$core$Result$andThen, + can_afford, + A2($elm$core$Result$andThen, is_valid, road)); + var finish_road = function (m) { + if (result.$ === 'Err') { + return m; + } else { + var rroad = result.a; + return A4( + $author$project$App$spend_items, + '🪨', + cost, + id1, + A2( + $author$project$App$update_map, + function (map) { + return _Utils_update( + map, + { + roads: A2($elm$core$List$cons, rroad, map.roads) + }); + }, + m)); + } + }; + return $author$project$App$change_selected_town( + finish_road(model)); + case 'DragItem': + var item = _v0.a; + var route = _v0.b; + var q = A2($elm$core$Debug$log, 'drop', item); + var ntowns = A3( + $elm_community$list_extra$List$Extra$updateAt, + item.town, + function (t) { + return _Utils_update( + t, + { + items: A2($elm$core$List$cons, item, t.items) + }); + }, + model.map.towns); + return A2( + $author$project$App$update_map, + function (map) { + return _Utils_update( + map, + {towns: ntowns}); + }, + A2( + $author$project$App$debug, + $elm$core$Debug$toString(item), + _Utils_update( + model, + { + selected_town: $elm$core$Maybe$Just(item.town) + }))); + default: + return model; + } +}; +var $elm_community$list_extra$List$Extra$find = F2( + function (predicate, list) { + find: + while (true) { + if (!list.b) { + return $elm$core$Maybe$Nothing; + } else { + var first = list.a; + var rest = list.b; + if (predicate(first)) { + return $elm$core$Maybe$Just(first); + } else { + var $temp$predicate = predicate, + $temp$list = rest; + predicate = $temp$predicate; + list = $temp$list; + continue find; + } + } + } + }); +var $author$project$App$Item = F2( + function (town, kind) { + return {kind: kind, town: town}; + }); +var $elm$core$Basics$min = F2( + function (x, y) { + return (_Utils_cmp(x, y) < 0) ? x : y; + }); +var $elm$core$Basics$e = _Basics_e; +var $author$project$App$poisson = function (lambda) { + var l = A2($elm$core$Basics$pow, $elm$core$Basics$e, -lambda); + var step = F2( + function (k, p) { + return A2( + $elm$random$Random$andThen, + function (u) { + var np = p * u; + return (_Utils_cmp(np, l) < 1) ? $elm$random$Random$constant(k - 1) : A2(step, k + 1, np); + }, + A2($elm$random$Random$float, 0, 1)); + }); + return A2(step, 0, 1); +}; +var $elm$core$List$maybeCons = F3( + function (f, mx, xs) { + var _v0 = f(mx); + if (_v0.$ === 'Just') { + var x = _v0.a; + return A2($elm$core$List$cons, x, xs); + } else { + return xs; + } + }); +var $elm$core$List$filterMap = F2( + function (f, xs) { + return A3( + $elm$core$List$foldr, + $elm$core$List$maybeCons(f), + _List_Nil, + xs); + }); +var $author$project$App$Recipe = F4( + function (in_buildings, in_items, out_buildings, out_items) { + return {in_buildings: in_buildings, in_items: in_items, out_buildings: out_buildings, out_items: out_items}; + }); +var $elm$parser$Parser$Advanced$Bad = F2( + function (a, b) { + return {$: 'Bad', a: a, b: b}; + }); +var $elm$parser$Parser$Advanced$Good = F3( + function (a, b, c) { + return {$: 'Good', a: a, b: b, c: c}; + }); +var $elm$parser$Parser$Advanced$Parser = function (a) { + return {$: 'Parser', a: a}; +}; +var $elm$parser$Parser$Advanced$map2 = F3( + function (func, _v0, _v1) { + var parseA = _v0.a; + var parseB = _v1.a; + return $elm$parser$Parser$Advanced$Parser( + function (s0) { + var _v2 = parseA(s0); + if (_v2.$ === 'Bad') { + var p = _v2.a; + var x = _v2.b; + return A2($elm$parser$Parser$Advanced$Bad, p, x); + } else { + var p1 = _v2.a; + var a = _v2.b; + var s1 = _v2.c; + var _v3 = parseB(s1); + if (_v3.$ === 'Bad') { + var p2 = _v3.a; + var x = _v3.b; + return A2($elm$parser$Parser$Advanced$Bad, p1 || p2, x); + } else { + var p2 = _v3.a; + var b = _v3.b; + var s2 = _v3.c; + return A3( + $elm$parser$Parser$Advanced$Good, + p1 || p2, + A2(func, a, b), + s2); + } + } + }); + }); +var $elm$parser$Parser$Advanced$ignorer = F2( + function (keepParser, ignoreParser) { + return A3($elm$parser$Parser$Advanced$map2, $elm$core$Basics$always, keepParser, ignoreParser); + }); +var $elm$parser$Parser$ignorer = $elm$parser$Parser$Advanced$ignorer; +var $elm$parser$Parser$Advanced$keeper = F2( + function (parseFunc, parseArg) { + return A3($elm$parser$Parser$Advanced$map2, $elm$core$Basics$apL, parseFunc, parseArg); + }); +var $elm$parser$Parser$keeper = $elm$parser$Parser$Advanced$keeper; +var $elm$parser$Parser$ExpectingKeyword = function (a) { + return {$: 'ExpectingKeyword', a: a}; +}; +var $elm$parser$Parser$Advanced$Token = F2( + function (a, b) { + return {$: 'Token', a: a, b: b}; + }); +var $elm$parser$Parser$Advanced$AddRight = F2( + function (a, b) { + return {$: 'AddRight', a: a, b: b}; + }); +var $elm$parser$Parser$Advanced$DeadEnd = F4( + function (row, col, problem, contextStack) { + return {col: col, contextStack: contextStack, problem: problem, row: row}; + }); +var $elm$parser$Parser$Advanced$Empty = {$: 'Empty'}; +var $elm$parser$Parser$Advanced$fromState = F2( + function (s, x) { + return A2( + $elm$parser$Parser$Advanced$AddRight, + $elm$parser$Parser$Advanced$Empty, + A4($elm$parser$Parser$Advanced$DeadEnd, s.row, s.col, x, s.context)); + }); +var $elm$parser$Parser$Advanced$isSubChar = _Parser_isSubChar; +var $elm$parser$Parser$Advanced$isSubString = _Parser_isSubString; +var $elm$parser$Parser$Advanced$keyword = function (_v0) { + var kwd = _v0.a; + var expecting = _v0.b; + var progress = !$elm$core$String$isEmpty(kwd); + return $elm$parser$Parser$Advanced$Parser( + function (s) { + var _v1 = A5($elm$parser$Parser$Advanced$isSubString, kwd, s.offset, s.row, s.col, s.src); + var newOffset = _v1.a; + var newRow = _v1.b; + var newCol = _v1.c; + return (_Utils_eq(newOffset, -1) || (0 <= A3( + $elm$parser$Parser$Advanced$isSubChar, + function (c) { + return $elm$core$Char$isAlphaNum(c) || _Utils_eq( + c, + _Utils_chr('_')); + }, + newOffset, + s.src))) ? A2( + $elm$parser$Parser$Advanced$Bad, + false, + A2($elm$parser$Parser$Advanced$fromState, s, expecting)) : A3( + $elm$parser$Parser$Advanced$Good, + progress, + _Utils_Tuple0, + {col: newCol, context: s.context, indent: s.indent, offset: newOffset, row: newRow, src: s.src}); + }); +}; +var $elm$parser$Parser$keyword = function (kwd) { + return $elm$parser$Parser$Advanced$keyword( + A2( + $elm$parser$Parser$Advanced$Token, + kwd, + $elm$parser$Parser$ExpectingKeyword(kwd))); +}; +var $elm$parser$Parser$Done = function (a) { + return {$: 'Done', a: a}; +}; +var $elm$parser$Parser$Loop = function (a) { + return {$: 'Loop', a: a}; +}; +var $elm$core$Set$Set_elm_builtin = function (a) { + return {$: 'Set_elm_builtin', a: a}; +}; +var $elm$core$Dict$RBEmpty_elm_builtin = {$: 'RBEmpty_elm_builtin'}; +var $elm$core$Dict$empty = $elm$core$Dict$RBEmpty_elm_builtin; +var $elm$core$Set$empty = $elm$core$Set$Set_elm_builtin($elm$core$Dict$empty); +var $elm$parser$Parser$ExpectingInt = {$: 'ExpectingInt'}; +var $elm$parser$Parser$Advanced$consumeBase = _Parser_consumeBase; +var $elm$parser$Parser$Advanced$consumeBase16 = _Parser_consumeBase16; +var $elm$parser$Parser$Advanced$bumpOffset = F2( + function (newOffset, s) { + return {col: s.col + (newOffset - s.offset), context: s.context, indent: s.indent, offset: newOffset, row: s.row, src: s.src}; + }); +var $elm$parser$Parser$Advanced$chompBase10 = _Parser_chompBase10; +var $elm$parser$Parser$Advanced$isAsciiCode = _Parser_isAsciiCode; +var $elm$parser$Parser$Advanced$consumeExp = F2( + function (offset, src) { + if (A3($elm$parser$Parser$Advanced$isAsciiCode, 101, offset, src) || A3($elm$parser$Parser$Advanced$isAsciiCode, 69, offset, src)) { + var eOffset = offset + 1; + var expOffset = (A3($elm$parser$Parser$Advanced$isAsciiCode, 43, eOffset, src) || A3($elm$parser$Parser$Advanced$isAsciiCode, 45, eOffset, src)) ? (eOffset + 1) : eOffset; + var newOffset = A2($elm$parser$Parser$Advanced$chompBase10, expOffset, src); + return _Utils_eq(expOffset, newOffset) ? (-newOffset) : newOffset; + } else { + return offset; + } + }); +var $elm$parser$Parser$Advanced$consumeDotAndExp = F2( + function (offset, src) { + return A3($elm$parser$Parser$Advanced$isAsciiCode, 46, offset, src) ? A2( + $elm$parser$Parser$Advanced$consumeExp, + A2($elm$parser$Parser$Advanced$chompBase10, offset + 1, src), + src) : A2($elm$parser$Parser$Advanced$consumeExp, offset, src); + }); +var $elm$parser$Parser$Advanced$finalizeInt = F5( + function (invalid, handler, startOffset, _v0, s) { + var endOffset = _v0.a; + var n = _v0.b; + if (handler.$ === 'Err') { + var x = handler.a; + return A2( + $elm$parser$Parser$Advanced$Bad, + true, + A2($elm$parser$Parser$Advanced$fromState, s, x)); + } else { + var toValue = handler.a; + return _Utils_eq(startOffset, endOffset) ? A2( + $elm$parser$Parser$Advanced$Bad, + _Utils_cmp(s.offset, startOffset) < 0, + A2($elm$parser$Parser$Advanced$fromState, s, invalid)) : A3( + $elm$parser$Parser$Advanced$Good, + true, + toValue(n), + A2($elm$parser$Parser$Advanced$bumpOffset, endOffset, s)); + } + }); +var $elm$parser$Parser$Advanced$fromInfo = F4( + function (row, col, x, context) { + return A2( + $elm$parser$Parser$Advanced$AddRight, + $elm$parser$Parser$Advanced$Empty, + A4($elm$parser$Parser$Advanced$DeadEnd, row, col, x, context)); + }); +var $elm$core$String$toFloat = _String_toFloat; +var $elm$parser$Parser$Advanced$finalizeFloat = F6( + function (invalid, expecting, intSettings, floatSettings, intPair, s) { + var intOffset = intPair.a; + var floatOffset = A2($elm$parser$Parser$Advanced$consumeDotAndExp, intOffset, s.src); + if (floatOffset < 0) { + return A2( + $elm$parser$Parser$Advanced$Bad, + true, + A4($elm$parser$Parser$Advanced$fromInfo, s.row, s.col - (floatOffset + s.offset), invalid, s.context)); + } else { + if (_Utils_eq(s.offset, floatOffset)) { + return A2( + $elm$parser$Parser$Advanced$Bad, + false, + A2($elm$parser$Parser$Advanced$fromState, s, expecting)); + } else { + if (_Utils_eq(intOffset, floatOffset)) { + return A5($elm$parser$Parser$Advanced$finalizeInt, invalid, intSettings, s.offset, intPair, s); + } else { + if (floatSettings.$ === 'Err') { + var x = floatSettings.a; + return A2( + $elm$parser$Parser$Advanced$Bad, + true, + A2($elm$parser$Parser$Advanced$fromState, s, invalid)); + } else { + var toValue = floatSettings.a; + var _v1 = $elm$core$String$toFloat( + A3($elm$core$String$slice, s.offset, floatOffset, s.src)); + if (_v1.$ === 'Nothing') { + return A2( + $elm$parser$Parser$Advanced$Bad, + true, + A2($elm$parser$Parser$Advanced$fromState, s, invalid)); + } else { + var n = _v1.a; + return A3( + $elm$parser$Parser$Advanced$Good, + true, + toValue(n), + A2($elm$parser$Parser$Advanced$bumpOffset, floatOffset, s)); + } + } + } + } + } + }); +var $elm$parser$Parser$Advanced$number = function (c) { + return $elm$parser$Parser$Advanced$Parser( + function (s) { + if (A3($elm$parser$Parser$Advanced$isAsciiCode, 48, s.offset, s.src)) { + var zeroOffset = s.offset + 1; + var baseOffset = zeroOffset + 1; + return A3($elm$parser$Parser$Advanced$isAsciiCode, 120, zeroOffset, s.src) ? A5( + $elm$parser$Parser$Advanced$finalizeInt, + c.invalid, + c.hex, + baseOffset, + A2($elm$parser$Parser$Advanced$consumeBase16, baseOffset, s.src), + s) : (A3($elm$parser$Parser$Advanced$isAsciiCode, 111, zeroOffset, s.src) ? A5( + $elm$parser$Parser$Advanced$finalizeInt, + c.invalid, + c.octal, + baseOffset, + A3($elm$parser$Parser$Advanced$consumeBase, 8, baseOffset, s.src), + s) : (A3($elm$parser$Parser$Advanced$isAsciiCode, 98, zeroOffset, s.src) ? A5( + $elm$parser$Parser$Advanced$finalizeInt, + c.invalid, + c.binary, + baseOffset, + A3($elm$parser$Parser$Advanced$consumeBase, 2, baseOffset, s.src), + s) : A6( + $elm$parser$Parser$Advanced$finalizeFloat, + c.invalid, + c.expecting, + c._int, + c._float, + _Utils_Tuple2(zeroOffset, 0), + s))); + } else { + return A6( + $elm$parser$Parser$Advanced$finalizeFloat, + c.invalid, + c.expecting, + c._int, + c._float, + A3($elm$parser$Parser$Advanced$consumeBase, 10, s.offset, s.src), + s); + } + }); +}; +var $elm$parser$Parser$Advanced$int = F2( + function (expecting, invalid) { + return $elm$parser$Parser$Advanced$number( + { + binary: $elm$core$Result$Err(invalid), + expecting: expecting, + _float: $elm$core$Result$Err(invalid), + hex: $elm$core$Result$Err(invalid), + _int: $elm$core$Result$Ok($elm$core$Basics$identity), + invalid: invalid, + octal: $elm$core$Result$Err(invalid) + }); + }); +var $elm$parser$Parser$int = A2($elm$parser$Parser$Advanced$int, $elm$parser$Parser$ExpectingInt, $elm$parser$Parser$ExpectingInt); +var $elm$parser$Parser$Advanced$loopHelp = F4( + function (p, state, callback, s0) { + loopHelp: + while (true) { + var _v0 = callback(state); + var parse = _v0.a; + var _v1 = parse(s0); + if (_v1.$ === 'Good') { + var p1 = _v1.a; + var step = _v1.b; + var s1 = _v1.c; + if (step.$ === 'Loop') { + var newState = step.a; + var $temp$p = p || p1, + $temp$state = newState, + $temp$callback = callback, + $temp$s0 = s1; + p = $temp$p; + state = $temp$state; + callback = $temp$callback; + s0 = $temp$s0; + continue loopHelp; + } else { + var result = step.a; + return A3($elm$parser$Parser$Advanced$Good, p || p1, result, s1); + } + } else { + var p1 = _v1.a; + var x = _v1.b; + return A2($elm$parser$Parser$Advanced$Bad, p || p1, x); + } + } + }); +var $elm$parser$Parser$Advanced$loop = F2( + function (state, callback) { + return $elm$parser$Parser$Advanced$Parser( + function (s) { + return A4($elm$parser$Parser$Advanced$loopHelp, false, state, callback, s); + }); + }); +var $elm$parser$Parser$Advanced$map = F2( + function (func, _v0) { + var parse = _v0.a; + return $elm$parser$Parser$Advanced$Parser( + function (s0) { + var _v1 = parse(s0); + if (_v1.$ === 'Good') { + var p = _v1.a; + var a = _v1.b; + var s1 = _v1.c; + return A3( + $elm$parser$Parser$Advanced$Good, + p, + func(a), + s1); + } else { + var p = _v1.a; + var x = _v1.b; + return A2($elm$parser$Parser$Advanced$Bad, p, x); + } + }); + }); +var $elm$parser$Parser$map = $elm$parser$Parser$Advanced$map; +var $elm$parser$Parser$Advanced$Done = function (a) { + return {$: 'Done', a: a}; +}; +var $elm$parser$Parser$Advanced$Loop = function (a) { + return {$: 'Loop', a: a}; +}; +var $elm$parser$Parser$toAdvancedStep = function (step) { + if (step.$ === 'Loop') { + var s = step.a; + return $elm$parser$Parser$Advanced$Loop(s); + } else { + var a = step.a; + return $elm$parser$Parser$Advanced$Done(a); + } +}; +var $elm$parser$Parser$loop = F2( + function (state, callback) { + return A2( + $elm$parser$Parser$Advanced$loop, + state, + function (s) { + return A2( + $elm$parser$Parser$map, + $elm$parser$Parser$toAdvancedStep, + callback(s)); + }); + }); +var $elm$parser$Parser$Advanced$Append = F2( + function (a, b) { + return {$: 'Append', a: a, b: b}; + }); +var $elm$parser$Parser$Advanced$oneOfHelp = F3( + function (s0, bag, parsers) { + oneOfHelp: + while (true) { + if (!parsers.b) { + return A2($elm$parser$Parser$Advanced$Bad, false, bag); + } else { + var parse = parsers.a.a; + var remainingParsers = parsers.b; + var _v1 = parse(s0); + if (_v1.$ === 'Good') { + var step = _v1; + return step; + } else { + var step = _v1; + var p = step.a; + var x = step.b; + if (p) { + return step; + } else { + var $temp$s0 = s0, + $temp$bag = A2($elm$parser$Parser$Advanced$Append, bag, x), + $temp$parsers = remainingParsers; + s0 = $temp$s0; + bag = $temp$bag; + parsers = $temp$parsers; + continue oneOfHelp; + } + } + } + } + }); +var $elm$parser$Parser$Advanced$oneOf = function (parsers) { + return $elm$parser$Parser$Advanced$Parser( + function (s) { + return A3($elm$parser$Parser$Advanced$oneOfHelp, s, $elm$parser$Parser$Advanced$Empty, parsers); + }); +}; +var $elm$parser$Parser$oneOf = $elm$parser$Parser$Advanced$oneOf; +var $elm$parser$Parser$Advanced$succeed = function (a) { + return $elm$parser$Parser$Advanced$Parser( + function (s) { + return A3($elm$parser$Parser$Advanced$Good, false, a, s); + }); +}; +var $elm$parser$Parser$succeed = $elm$parser$Parser$Advanced$succeed; +var $elm$parser$Parser$ExpectingVariable = {$: 'ExpectingVariable'}; +var $elm$core$Basics$compare = _Utils_compare; +var $elm$core$Dict$get = F2( + function (targetKey, dict) { + get: + while (true) { + if (dict.$ === 'RBEmpty_elm_builtin') { + return $elm$core$Maybe$Nothing; + } else { + var key = dict.b; + var value = dict.c; + var left = dict.d; + var right = dict.e; + var _v1 = A2($elm$core$Basics$compare, targetKey, key); + switch (_v1.$) { + case 'LT': + var $temp$targetKey = targetKey, + $temp$dict = left; + targetKey = $temp$targetKey; + dict = $temp$dict; + continue get; + case 'EQ': + return $elm$core$Maybe$Just(value); + default: + var $temp$targetKey = targetKey, + $temp$dict = right; + targetKey = $temp$targetKey; + dict = $temp$dict; + continue get; + } + } + } + }); +var $elm$core$Dict$member = F2( + function (key, dict) { + var _v0 = A2($elm$core$Dict$get, key, dict); + if (_v0.$ === 'Just') { + return true; + } else { + return false; + } + }); +var $elm$core$Set$member = F2( + function (key, _v0) { + var dict = _v0.a; + return A2($elm$core$Dict$member, key, dict); + }); +var $elm$parser$Parser$Advanced$varHelp = F7( + function (isGood, offset, row, col, src, indent, context) { + varHelp: + while (true) { + var newOffset = A3($elm$parser$Parser$Advanced$isSubChar, isGood, offset, src); + if (_Utils_eq(newOffset, -1)) { + return {col: col, context: context, indent: indent, offset: offset, row: row, src: src}; + } else { + if (_Utils_eq(newOffset, -2)) { + var $temp$isGood = isGood, + $temp$offset = offset + 1, + $temp$row = row + 1, + $temp$col = 1, + $temp$src = src, + $temp$indent = indent, + $temp$context = context; + isGood = $temp$isGood; + offset = $temp$offset; + row = $temp$row; + col = $temp$col; + src = $temp$src; + indent = $temp$indent; + context = $temp$context; + continue varHelp; + } else { + var $temp$isGood = isGood, + $temp$offset = newOffset, + $temp$row = row, + $temp$col = col + 1, + $temp$src = src, + $temp$indent = indent, + $temp$context = context; + isGood = $temp$isGood; + offset = $temp$offset; + row = $temp$row; + col = $temp$col; + src = $temp$src; + indent = $temp$indent; + context = $temp$context; + continue varHelp; + } + } + } + }); +var $elm$parser$Parser$Advanced$variable = function (i) { + return $elm$parser$Parser$Advanced$Parser( + function (s) { + var firstOffset = A3($elm$parser$Parser$Advanced$isSubChar, i.start, s.offset, s.src); + if (_Utils_eq(firstOffset, -1)) { + return A2( + $elm$parser$Parser$Advanced$Bad, + false, + A2($elm$parser$Parser$Advanced$fromState, s, i.expecting)); + } else { + var s1 = _Utils_eq(firstOffset, -2) ? A7($elm$parser$Parser$Advanced$varHelp, i.inner, s.offset + 1, s.row + 1, 1, s.src, s.indent, s.context) : A7($elm$parser$Parser$Advanced$varHelp, i.inner, firstOffset, s.row, s.col + 1, s.src, s.indent, s.context); + var name = A3($elm$core$String$slice, s.offset, s1.offset, s.src); + return A2($elm$core$Set$member, name, i.reserved) ? A2( + $elm$parser$Parser$Advanced$Bad, + false, + A2($elm$parser$Parser$Advanced$fromState, s, i.expecting)) : A3($elm$parser$Parser$Advanced$Good, true, name, s1); + } + }); +}; +var $elm$parser$Parser$variable = function (i) { + return $elm$parser$Parser$Advanced$variable( + {expecting: $elm$parser$Parser$ExpectingVariable, inner: i.inner, reserved: i.reserved, start: i.start}); +}; +var $author$project$App$parse_symbol_list = A2( + $elm$parser$Parser$loop, + _List_Nil, + function (l) { + return $elm$parser$Parser$oneOf( + _List_fromArray( + [ + A2( + $elm$parser$Parser$keeper, + $elm$parser$Parser$succeed( + function (_v0) { + var symbol = _v0.a; + var count = _v0.b; + return $elm$parser$Parser$Loop( + (symbol === '.') ? l : A2( + $elm$core$List$cons, + _Utils_Tuple2(symbol, count), + l)); + }), + A2( + $elm$parser$Parser$keeper, + A2( + $elm$parser$Parser$keeper, + $elm$parser$Parser$succeed($elm$core$Tuple$pair), + $elm$parser$Parser$variable( + { + inner: function (c) { + return !($elm$core$Char$isDigit(c) || _Utils_eq( + c, + _Utils_chr(' '))); + }, + reserved: $elm$core$Set$empty, + start: function (c) { + return !($elm$core$Char$isDigit(c) || _Utils_eq( + c, + _Utils_chr(' '))); + } + })), + $elm$parser$Parser$oneOf( + _List_fromArray( + [ + $elm$parser$Parser$int, + $elm$parser$Parser$succeed(1) + ])))), + A2( + $elm$parser$Parser$map, + function (_v1) { + return $elm$parser$Parser$Done( + $elm$core$List$reverse(l)); + }, + $elm$parser$Parser$succeed(_Utils_Tuple0)) + ])); + }); +var $elm$parser$Parser$Advanced$chompWhileHelp = F5( + function (isGood, offset, row, col, s0) { + chompWhileHelp: + while (true) { + var newOffset = A3($elm$parser$Parser$Advanced$isSubChar, isGood, offset, s0.src); + if (_Utils_eq(newOffset, -1)) { + return A3( + $elm$parser$Parser$Advanced$Good, + _Utils_cmp(s0.offset, offset) < 0, + _Utils_Tuple0, + {col: col, context: s0.context, indent: s0.indent, offset: offset, row: row, src: s0.src}); + } else { + if (_Utils_eq(newOffset, -2)) { + var $temp$isGood = isGood, + $temp$offset = offset + 1, + $temp$row = row + 1, + $temp$col = 1, + $temp$s0 = s0; + isGood = $temp$isGood; + offset = $temp$offset; + row = $temp$row; + col = $temp$col; + s0 = $temp$s0; + continue chompWhileHelp; + } else { + var $temp$isGood = isGood, + $temp$offset = newOffset, + $temp$row = row, + $temp$col = col + 1, + $temp$s0 = s0; + isGood = $temp$isGood; + offset = $temp$offset; + row = $temp$row; + col = $temp$col; + s0 = $temp$s0; + continue chompWhileHelp; + } + } + } + }); +var $elm$parser$Parser$Advanced$chompWhile = function (isGood) { + return $elm$parser$Parser$Advanced$Parser( + function (s) { + return A5($elm$parser$Parser$Advanced$chompWhileHelp, isGood, s.offset, s.row, s.col, s); + }); +}; +var $elm$parser$Parser$Advanced$spaces = $elm$parser$Parser$Advanced$chompWhile( + function (c) { + return _Utils_eq( + c, + _Utils_chr(' ')) || (_Utils_eq( + c, + _Utils_chr('\n')) || _Utils_eq( + c, + _Utils_chr('\r'))); + }); +var $elm$parser$Parser$spaces = $elm$parser$Parser$Advanced$spaces; +var $author$project$App$parse_recipe = A2( + $elm$parser$Parser$keeper, + A2( + $elm$parser$Parser$keeper, + A2( + $elm$parser$Parser$keeper, + A2( + $elm$parser$Parser$keeper, + $elm$parser$Parser$succeed($author$project$App$Recipe), + A2( + $elm$parser$Parser$ignorer, + A2( + $elm$parser$Parser$ignorer, + $author$project$App$parse_symbol_list, + $elm$parser$Parser$keyword(' ')), + $elm$parser$Parser$spaces)), + A2( + $elm$parser$Parser$ignorer, + A2( + $elm$parser$Parser$ignorer, + $author$project$App$parse_symbol_list, + $elm$parser$Parser$keyword(' ')), + $elm$parser$Parser$spaces)), + A2( + $elm$parser$Parser$ignorer, + A2( + $elm$parser$Parser$ignorer, + $author$project$App$parse_symbol_list, + $elm$parser$Parser$keyword(' ')), + $elm$parser$Parser$spaces)), + $author$project$App$parse_symbol_list); +var $elm$parser$Parser$DeadEnd = F3( + function (row, col, problem) { + return {col: col, problem: problem, row: row}; + }); +var $elm$parser$Parser$problemToDeadEnd = function (p) { + return A3($elm$parser$Parser$DeadEnd, p.row, p.col, p.problem); +}; +var $elm$parser$Parser$Advanced$bagToList = F2( + function (bag, list) { + bagToList: + while (true) { + switch (bag.$) { + case 'Empty': + return list; + case 'AddRight': + var bag1 = bag.a; + var x = bag.b; + var $temp$bag = bag1, + $temp$list = A2($elm$core$List$cons, x, list); + bag = $temp$bag; + list = $temp$list; + continue bagToList; + default: + var bag1 = bag.a; + var bag2 = bag.b; + var $temp$bag = bag1, + $temp$list = A2($elm$parser$Parser$Advanced$bagToList, bag2, list); + bag = $temp$bag; + list = $temp$list; + continue bagToList; + } + } + }); +var $elm$parser$Parser$Advanced$run = F2( + function (_v0, src) { + var parse = _v0.a; + var _v1 = parse( + {col: 1, context: _List_Nil, indent: 1, offset: 0, row: 1, src: src}); + if (_v1.$ === 'Good') { + var value = _v1.b; + return $elm$core$Result$Ok(value); + } else { + var bag = _v1.b; + return $elm$core$Result$Err( + A2($elm$parser$Parser$Advanced$bagToList, bag, _List_Nil)); + } + }); +var $elm$parser$Parser$run = F2( + function (parser, source) { + var _v0 = A2($elm$parser$Parser$Advanced$run, parser, source); + if (_v0.$ === 'Ok') { + var a = _v0.a; + return $elm$core$Result$Ok(a); + } else { + var problems = _v0.a; + return $elm$core$Result$Err( + A2($elm$core$List$map, $elm$parser$Parser$problemToDeadEnd, problems)); + } + }); +var $elm$core$Result$toMaybe = function (result) { + if (result.$ === 'Ok') { + var v = result.a; + return $elm$core$Maybe$Just(v); + } else { + return $elm$core$Maybe$Nothing; + } +}; +var $author$project$App$recipes = A2( + $elm$core$List$filterMap, + A2( + $elm$core$Basics$composeR, + $elm$parser$Parser$run($author$project$App$parse_recipe), + $elm$core$Result$toMaybe), + _List_fromArray( + ['⛺1 🧍1🌲1🌿1 🛖 🧍1', '. 🧍1🌲1 ⛺1 🧍1', '. 🧍1🌲1 . 🧍1🔥1', '🛖1 🧍1🪨1🔥1 🛖 🧍1🧱', '⛺1 🧍1🧱3🌲2 🏠1 🧍1', '🏠3 . 🏘️1 .', '🏠1 🍞3 . 🧍1', '. 🧍1 . 🧍1🪨1', '. 🧍1🌲1 . 🧍1🌱2', '. 🌱1 . 🌲1', '. 🔥1🌱1 . 🌿1', '. 🔥1🌿1 . 🍞1'])); +var $elm_community$random_extra$Random$Extra$sequence = A2( + $elm$core$List$foldr, + $elm$random$Random$map2($elm$core$List$cons), + $elm$random$Random$constant(_List_Nil)); +var $author$project$App$next_turn = function (original_map) { + var turn_town = function (town) { + var rate = 0.9; + var random_item_kinds = _List_fromArray( + ['🌲', '🌿']); + var num_items = $elm$core$List$length(town.items); + var max_items = 3; + var num_new_items = A2( + $elm$random$Random$map, + $elm$core$Basics$min(max_items - num_items), + $author$project$App$poisson(rate)); + var available_recipes = A2( + $elm$core$List$filter, + $author$project$App$can_afford_recipe(town), + $author$project$App$recipes); + var _v0 = function () { + if (!random_item_kinds.b) { + return _Utils_Tuple2('', _List_Nil); + } else { + var a = random_item_kinds.a; + var rest = random_item_kinds.b; + return _Utils_Tuple2(a, rest); + } + }(); + var k1 = _v0.a; + var rest_kinds = _v0.b; + var new_item = A3( + $elm$random$Random$map2, + $author$project$App$Item, + $elm$random$Random$constant(town.id), + A2($elm$random$Random$uniform, k1, rest_kinds)); + var new_items = A2( + $elm$random$Random$andThen, + function (n) { + return A2($elm$random$Random$list, n, new_item); + }, + num_new_items); + var add_new_items = function (t) { + return A2( + $elm$random$Random$map, + function (items) { + return _Utils_update( + t, + { + items: _Utils_ap(items, t.items) + }); + }, + new_items); + }; + return A2( + $elm$random$Random$andThen, + add_new_items, + $elm$random$Random$constant(town)); + }; + var turn_towns = function (map) { + return A2( + $elm$random$Random$map, + function (towns) { + return _Utils_update( + map, + {towns: towns}); + }, + $elm_community$random_extra$Random$Extra$sequence( + A2($elm$core$List$map, turn_town, map.towns))); + }; + return A2( + $elm$random$Random$andThen, + turn_towns, + $elm$random$Random$constant(original_map)); +}; +var $elm$core$Platform$Cmd$batch = _Platform_batch; +var $elm$core$Platform$Cmd$none = $elm$core$Platform$Cmd$batch(_List_Nil); +var $author$project$App$nocmd = function (model) { + return _Utils_Tuple2(model, $elm$core$Platform$Cmd$none); +}; +var $author$project$App$oneOfMaybes = function (maybes) { + oneOfMaybes: + while (true) { + if (!maybes.b) { + return $elm$core$Maybe$Nothing; + } else { + if (maybes.a.$ === 'Nothing') { + var _v1 = maybes.a; + var rest = maybes.b; + var $temp$maybes = rest; + maybes = $temp$maybes; + continue oneOfMaybes; + } else { + var a = maybes.a.a; + var rest = maybes.b; + return $elm$core$Maybe$Just(a); + } + } + } +}; +var $elm_community$list_extra$List$Extra$removeAt = F2( + function (index, l) { + if (index < 0) { + return l; + } else { + var _v0 = A2($elm$core$List$drop, index, l); + if (!_v0.b) { + return l; + } else { + var rest = _v0.b; + return _Utils_ap( + A2($elm$core$List$take, index, l), + rest); + } + } + }); +var $elm$core$Basics$cos = _Basics_cos; +var $elm_community$list_extra$List$Extra$findIndexHelp = F3( + function (index, predicate, list) { + findIndexHelp: + while (true) { + if (!list.b) { + return $elm$core$Maybe$Nothing; + } else { + var x = list.a; + var xs = list.b; + if (predicate(x)) { + return $elm$core$Maybe$Just(index); + } else { + var $temp$index = index + 1, + $temp$predicate = predicate, + $temp$list = xs; + index = $temp$index; + predicate = $temp$predicate; + list = $temp$list; + continue findIndexHelp; + } + } + } + }); +var $elm_community$list_extra$List$Extra$findIndex = $elm_community$list_extra$List$Extra$findIndexHelp(0); +var $elm_community$list_extra$List$Extra$elemIndex = function (x) { + return $elm_community$list_extra$List$Extra$findIndex( + $elm$core$Basics$eq(x)); +}; +var $author$project$App$item_kinds = _List_fromArray( + ['🌲', '🌱', '🌿', '🪨', '🧱', '🔥', '🧍', '🍞']); +var $elm$core$Basics$pi = _Basics_pi; +var $elm$core$Basics$sin = _Basics_sin; +var $author$project$App$item_position = F2( + function (town, kind) { + var r = 2; + var i = A2( + $elm$core$Maybe$withDefault, + 0, + A2($elm_community$list_extra$List$Extra$elemIndex, kind, $author$project$App$item_kinds)); + var an = (($author$project$Util$tf(i) / $author$project$Util$tf( + $elm$core$List$length($author$project$App$item_kinds) - 1)) * ((2 * $elm$core$Basics$pi) / 3)) + ($elm$core$Basics$pi / 6); + var x = r * $elm$core$Basics$cos(an); + var y = r * $elm$core$Basics$sin(an); + return _Utils_Tuple2(x, y); + }); +var $author$project$App$positioned_items = function (map) { + return A2( + $elm$core$List$concatMap, + function (t) { + return A2( + $elm$core$List$indexedMap, + F2( + function (i, item) { + return _Utils_Tuple3( + item, + i, + A2( + $author$project$Vector$add, + t.position, + A2($author$project$App$item_position, t, item.kind))); + }), + t.items); + }, + map.towns); +}; +var $author$project$App$select_item = function (model) { + var items = $author$project$App$positioned_items(model.map); + return A2( + $elm$core$Maybe$map, + $author$project$Util$third, + A4( + $author$project$Vector$closest_within, + function (_v0) { + return 1.5; + }, + $author$project$Util$third, + $author$project$App$projected_pointer(model), + items)); +}; +var $author$project$App$set_blank_click = function (model) { + return _Utils_update( + model, + {click_mode: $author$project$App$BlankClick}); +}; +var $author$project$App$set_pointer = F2( + function (pos, model) { + return _Utils_update( + model, + {pointer: pos}); + }); +var $elm$core$Basics$clamp = F3( + function (low, high, number) { + return (_Utils_cmp(number, low) < 0) ? low : ((_Utils_cmp(number, high) > 0) ? high : number); + }); +var $author$project$Vector$dot = F2( + function (_v0, _v1) { + var x1 = _v0.a; + var y1 = _v0.b; + var x2 = _v1.a; + var y2 = _v1.b; + return (x1 * x2) + (y1 * y2); + }); +var $author$project$Vector$closest_point_on_segment = F2( + function (_v0, p) { + var p1 = _v0.a; + var p2 = _v0.b; + var vp = A2($author$project$Vector$sub, p, p1); + var v = A2($author$project$Vector$sub, p2, p1); + var l = $author$project$Vector$len(v); + var d = A2($author$project$Vector$dot, v, vp) / A2( + $elm$core$Basics$pow, + $author$project$Vector$len(v), + 2); + var t = A3($elm$core$Basics$clamp, 0, 1, d); + return _Utils_Tuple2( + d, + A2( + $author$project$Vector$add, + p1, + A2($author$project$Vector$smul, t, v))); + }); +var $elm_community$list_extra$List$Extra$minimumBy = F2( + function (f, ls) { + var minBy = F2( + function (x, _v1) { + var y = _v1.a; + var fy = _v1.b; + var fx = f(x); + return (_Utils_cmp(fx, fy) < 0) ? _Utils_Tuple2(x, fx) : _Utils_Tuple2(y, fy); + }); + if (ls.b) { + if (!ls.b.b) { + var l_ = ls.a; + return $elm$core$Maybe$Just(l_); + } else { + var l_ = ls.a; + var ls_ = ls.b; + return $elm$core$Maybe$Just( + A3( + $elm$core$List$foldl, + minBy, + _Utils_Tuple2( + l_, + f(l_)), + ls_).a); + } + } else { + return $elm$core$Maybe$Nothing; + } + }); +var $author$project$App$closest_point_to_road = F2( + function (road, p) { + var path = road.c; + return A2( + $elm_community$list_extra$List$Extra$minimumBy, + function (cp) { + return $author$project$Vector$len( + A2($author$project$Vector$sub, p, cp)); + }, + A2( + $elm$core$List$map, + function (segment) { + return A2($author$project$Vector$closest_point_on_segment, segment, p).b; + }, + A3( + $elm$core$List$map2, + $elm$core$Tuple$pair, + path, + A2($elm$core$List$drop, 1, path)))); + }); +var $author$project$App$distance_of_point_on_road = F2( + function (road, p) { + var original_path = road.c; + var fn = F2( + function (d, path) { + fn: + while (true) { + if (!path.b) { + return 0; + } else { + if (!path.b.b) { + var a = path.a; + return d; + } else { + var a = path.a; + var _v2 = path.b; + var b = _v2.a; + var rest = _v2.b; + var l = A2($author$project$Vector$distance, a, b); + var _v3 = A2( + $author$project$Vector$closest_point_on_segment, + _Utils_Tuple2(a, b), + p); + var t = _v3.a; + var cp = _v3.b; + var dp = A2($author$project$Vector$distance, p, cp); + if (dp < 0.1) { + return d + (t * l); + } else { + var $temp$d = d + l, + $temp$path = A2($elm$core$List$cons, b, rest); + d = $temp$d; + path = $temp$path; + continue fn; + } + } + } + } + }); + return A2(fn, 0, original_path); + }); +var $author$project$App$roads_at_town = F2( + function (model, id) { + return A2( + $elm$core$List$filter, + function (r) { + var from = r.a; + var to = r.b; + return _Utils_eq(from, id) || _Utils_eq(to, id); + }, + model.map.roads); + }); +var $author$project$App$drag_item_position = F2( + function (model, item) { + var roads = A2($author$project$App$roads_at_town, model, item.town); + var pointer = $author$project$App$projected_pointer(model); + return $elm$core$List$head( + A2( + $elm$core$List$sortBy, + A2( + $elm$core$Basics$composeR, + $elm$core$Tuple$second, + A2( + $elm$core$Basics$composeR, + $author$project$Vector$sub(pointer), + $author$project$Vector$len)), + A2( + $elm$core$List$filterMap, + function (r) { + return A2( + $elm$core$Maybe$map, + $elm$core$Tuple$pair(r), + A2($author$project$App$closest_point_to_road, r, pointer)); + }, + roads))); + }); +var $elm$core$Maybe$map2 = F3( + function (func, ma, mb) { + if (ma.$ === 'Nothing') { + return $elm$core$Maybe$Nothing; + } else { + var a = ma.a; + if (mb.$ === 'Nothing') { + return $elm$core$Maybe$Nothing; + } else { + var b = mb.a; + return $elm$core$Maybe$Just( + A2(func, a, b)); + } + } + }); +var $author$project$App$update_click_mode = function (model) { + var pointer = $author$project$App$projected_pointer(model); + var mode = function () { + var _v1 = model.click_mode; + switch (_v1.$) { + case 'BlankClick': + return $author$project$App$BlankClick; + case 'DragRoad': + var i = _v1.a; + var path = _v1.b; + return A2( + $author$project$App$DragRoad, + i, + A2($elm$core$List$cons, pointer, path)); + case 'PanCamera': + var v = _v1.a; + return $author$project$App$PanCamera(model.pointer); + default: + var item = _v1.a; + var route = _v1.b; + var mroad = _v1.c; + if (mroad.$ === 'Nothing') { + var mt = A2($author$project$App$get_town, model, item.town); + var mcp = A2($author$project$App$drag_item_position, model, item); + var nmroad = function () { + if (mcp.$ === 'Nothing') { + return $elm$core$Maybe$Nothing; + } else { + var _v9 = mcp.a; + var r = _v9.a; + var path = r.c; + var v = _v9.b; + var total = $author$project$App$total_length(path); + var md = A2( + $elm$core$Maybe$map, + A2( + $elm$core$Basics$composeR, + function ($) { + return $.position; + }, + $author$project$Vector$distance(v)), + mt); + var dr = A2($author$project$App$distance_of_point_on_road, r, v); + return A2( + $elm$core$Maybe$andThen, + function (_v10) { + var t = _v10.a; + var d = _v10.b; + return ((dr > 1) && (_Utils_cmp(dr, total - 1) < 0)) ? $elm$core$Maybe$Just( + _Utils_Tuple2(r, dr)) : $elm$core$Maybe$Nothing; + }, + A3($elm$core$Maybe$map2, $elm$core$Tuple$pair, mt, md)); + } + }(); + var nroute = function () { + if (nmroad.$ === 'Nothing') { + return route; + } else { + var _v4 = nmroad.a; + var _v5 = _v4.a; + var from = _v5.a; + var to = _v5.b; + if (route.b && route.b.b) { + var a = route.a; + var _v7 = route.b; + var b = _v7.a; + var rest = _v7.b; + return (_Utils_eq(a, item.town) && ((_Utils_eq(a, from) && _Utils_eq(b, to)) || (_Utils_eq(a, to) && _Utils_eq(b, from)))) ? A2($elm$core$List$cons, b, rest) : route; + } else { + return route; + } + } + }(); + return A3($author$project$App$DragItem, item, nroute, nmroad); + } else { + var _v11 = mroad.a; + var r = _v11.a; + var from = r.a; + var to = r.b; + var path = r.c; + var d = _v11.b; + var mt2 = A2($author$project$App$get_town, model, to); + var mt1 = A2($author$project$App$get_town, model, from); + var mcp = A2($author$project$App$closest_point_to_road, r, pointer); + var nd = A2( + $elm$core$Maybe$withDefault, + d, + A2( + $elm$core$Maybe$map, + $author$project$App$distance_of_point_on_road(r), + mcp)); + var mclosest = $elm$core$List$head( + A2( + $elm$core$List$sortBy, + $elm$core$Tuple$second, + A2( + $elm$core$List$filterMap, + A2( + $elm$core$Basics$composeR, + $author$project$App$get_town(model), + A2( + $elm$core$Maybe$map2, + F2( + function (cp, t) { + return _Utils_Tuple2( + t, + A2($author$project$Vector$distance, cp, t.position)); + }), + mcp)), + _List_fromArray( + [from, to])))); + var max_move = 3; + var nnd = d + A3($elm$core$Basics$clamp, -max_move, max_move, nd - d); + if (mclosest.$ === 'Nothing') { + return A3( + $author$project$App$DragItem, + item, + route, + $elm$core$Maybe$Just( + _Utils_Tuple2(r, nnd))); + } else { + var _v13 = mclosest.a; + var t = _v13.a; + var td = _v13.b; + return (td < 1) ? A3( + $author$project$App$DragItem, + _Utils_update( + item, + {town: t.id}), + _Utils_eq( + $elm$core$List$head(route), + $elm$core$Maybe$Just(t.id)) ? route : A2($elm$core$List$cons, t.id, route), + $elm$core$Maybe$Nothing) : A3( + $author$project$App$DragItem, + item, + route, + $elm$core$Maybe$Just( + _Utils_Tuple2(r, nnd))); + } + } + } + }(); + var _v0 = model.click_mode; + if (_v0.$ === 'PanCamera') { + var p1 = _v0.a; + var d = A2( + $author$project$Vector$smul, + model.camera.zoom, + A2($author$project$Vector$sub, model.pointer, p1)); + var ncamera = { + pan: A2($author$project$Vector$add, d, model.camera.pan), + zoom: model.camera.zoom + }; + return _Utils_update( + model, + {camera: ncamera, click_mode: mode}); + } else { + return _Utils_update( + model, + {click_mode: mode}); + } +}; +var $author$project$App$update = F2( + function (msg, model) { + update: + while (true) { + switch (msg.$) { + case 'SetPosition': + var pos = msg.a; + return $author$project$App$nocmd( + $author$project$App$update_click_mode( + A2($author$project$App$set_pointer, pos, model))); + case 'PointerDown': + var towns = model.map.towns; + var _v1 = A2( + $elm$core$Maybe$withDefault, + _Utils_Tuple2( + $author$project$App$PanCamera(model.pointer), + towns), + $author$project$App$oneOfMaybes( + _List_fromArray( + [ + A2( + $elm$core$Maybe$map, + function (_v2) { + var item = _v2.a; + var i = _v2.b; + var pos = _v2.c; + return _Utils_Tuple2( + A3( + $author$project$App$DragItem, + item, + _List_fromArray( + [item.town]), + $elm$core$Maybe$Nothing), + A3( + $elm_community$list_extra$List$Extra$updateAt, + item.town, + function (t) { + return _Utils_update( + t, + { + items: A2($elm_community$list_extra$List$Extra$removeAt, i, t.items) + }); + }, + model.map.towns)); + }, + $author$project$App$select_item(model)), + A2( + $elm$core$Maybe$map, + function (_v3) { + var i = _v3.a; + var d = _v3.b; + var town = _v3.c; + return _Utils_Tuple2( + A2( + $author$project$App$DragRoad, + town.id, + _List_fromArray( + [town.position])), + towns); + }, + $author$project$App$select_town(model)) + ]))); + var mode = _v1.a; + var ntowns = _v1.b; + var _v4 = model.click_mode; + if (_v4.$ === 'BlankClick') { + return $author$project$App$nocmd( + A2( + $author$project$App$update_map, + function (map) { + return _Utils_update( + map, + {towns: ntowns}); + }, + A2( + $author$project$App$debug, + 'PointerDown', + _Utils_update( + model, + {click_mode: mode})))); + } else { + return $author$project$App$nocmd(model); + } + case 'PointerUp': + return $author$project$App$nocmd( + $author$project$App$set_blank_click( + $author$project$App$end_touch( + A2($author$project$App$debug, 'PointerUp', model)))); + case 'TouchStart': + var pos = msg.a; + var q = A2($elm$core$Debug$log, 'TouchStart', pos); + return A2( + $author$project$App$update, + $author$project$App$PointerDown, + A2( + $author$project$App$debug, + 'TouchStart', + _Utils_update( + model, + {pointer: pos}))); + case 'TouchEnd': + var q = A2($elm$core$Debug$log, 'TouchEnd', _Utils_Tuple0); + var $temp$msg = $author$project$App$PointerUp, + $temp$model = A2($author$project$App$debug, 'TouchEnd', model); + msg = $temp$msg; + model = $temp$model; + continue update; + case 'SetTool': + var tool = msg.a; + return $author$project$App$nocmd( + _Utils_update( + model, + {tool: tool})); + case 'SetMap': + var map = msg.a; + var person_town = A2( + $elm_community$list_extra$List$Extra$find, + A2( + $elm$core$Basics$composeR, + function ($) { + return $.items; + }, + $elm$core$List$any( + A2( + $elm$core$Basics$composeR, + function ($) { + return $.kind; + }, + $elm$core$Basics$eq('🧍')))), + map.towns); + var camera = function (c) { + if (person_town.$ === 'Just') { + var t = person_town.a; + return _Utils_update( + c, + { + pan: A2( + $author$project$Vector$sub, + _Utils_Tuple2(0, 0), + t.position) + }); + } else { + return c; + } + }(model.camera); + return $author$project$App$nocmd( + _Utils_update( + model, + {camera: camera, map: map})); + case 'ApplyRecipe': + var townid = msg.a; + var recipe = msg.b; + return $author$project$App$nocmd( + A3($author$project$App$apply_recipe, townid, recipe, model)); + case 'EndTurn': + return _Utils_Tuple2( + model, + A2( + $elm$random$Random$generate, + $author$project$App$SetMap, + $author$project$App$next_turn(model.map))); + default: + var v = msg.a; + var _v6 = A2( + $elm$json$Json$Decode$decodeValue, + $author$project$App$decode_touch_vector($author$project$App$TouchStart), + v); + if (_v6.$ === 'Ok') { + return $author$project$App$nocmd(model); + } else { + var err = _v6.a; + var q = A2($elm$core$Debug$log, 'err', err); + return $author$project$App$nocmd(model); + } + } + } + }); +var $author$project$App$ApplyRecipe = F2( + function (a, b) { + return {$: 'ApplyRecipe', a: a, b: b}; + }); +var $author$project$App$BadValue = function (a) { + return {$: 'BadValue', a: a}; +}; +var $author$project$App$EndTurn = {$: 'EndTurn'}; +var $author$project$App$SetPosition = function (a) { + return {$: 'SetPosition', a: a}; +}; +var $author$project$App$SetTool = function (a) { + return {$: 'SetTool', a: a}; +}; +var $author$project$App$TouchEnd = {$: 'TouchEnd'}; +var $elm$virtual_dom$VirtualDom$attribute = F2( + function (key, value) { + return A2( + _VirtualDom_attribute, + _VirtualDom_noOnOrFormAction(key), + _VirtualDom_noJavaScriptOrHtmlUri(value)); + }); +var $elm$html$Html$Attributes$attribute = $elm$virtual_dom$VirtualDom$attribute; +var $elm_community$list_extra$List$Extra$groupWhile = F2( + function (isSameGroup, items) { + return A3( + $elm$core$List$foldr, + F2( + function (x, acc) { + if (!acc.b) { + return _List_fromArray( + [ + _Utils_Tuple2(x, _List_Nil) + ]); + } else { + var _v1 = acc.a; + var y = _v1.a; + var restOfGroup = _v1.b; + var groups = acc.b; + return A2(isSameGroup, x, y) ? A2( + $elm$core$List$cons, + _Utils_Tuple2( + x, + A2($elm$core$List$cons, y, restOfGroup)), + groups) : A2( + $elm$core$List$cons, + _Utils_Tuple2(x, _List_Nil), + acc); + } + }), + _List_Nil, + items); + }); +var $elm_community$list_extra$List$Extra$group = $elm_community$list_extra$List$Extra$groupWhile($elm$core$Basics$eq); +var $elm$core$Tuple$mapSecond = F2( + function (func, _v0) { + var x = _v0.a; + var y = _v0.b; + return _Utils_Tuple2( + x, + func(y)); + }); +var $elm$core$List$sort = function (xs) { + return A2($elm$core$List$sortBy, $elm$core$Basics$identity, xs); +}; +var $author$project$App$count_kinds = A2( + $elm$core$Basics$composeR, + $elm$core$List$sort, + A2( + $elm$core$Basics$composeR, + $elm_community$list_extra$List$Extra$group, + $elm$core$List$map( + $elm$core$Tuple$mapSecond( + A2( + $elm$core$Basics$composeR, + $elm$core$List$length, + $elm$core$Basics$add(1)))))); +var $author$project$App$building_counts = function (town) { + return $author$project$App$count_kinds(town.buildings); +}; +var $author$project$App$building_kinds = _List_fromArray( + ['⛺', '🛖', '🏠']); +var $elm$html$Html$button = _VirtualDom_node('button'); +var $elm$core$String$toUpper = _String_toUpper; +var $author$project$Util$capitalise = function (str) { + return _Utils_ap( + $elm$core$String$toUpper( + A2($elm$core$String$left, 1, str)), + A2($elm$core$String$dropLeft, 1, str)); +}; +var $elm$json$Json$Encode$bool = _Json_wrap; +var $elm$html$Html$Attributes$boolProperty = F2( + function (key, bool) { + return A2( + _VirtualDom_property, + key, + $elm$json$Json$Encode$bool(bool)); + }); +var $elm$html$Html$Attributes$checked = $elm$html$Html$Attributes$boolProperty('checked'); +var $elm$svg$Svg$trustedNode = _VirtualDom_nodeNS('http://www.w3.org/2000/svg'); +var $elm$svg$Svg$circle = $elm$svg$Svg$trustedNode('circle'); +var $elm$svg$Svg$Attributes$class = _VirtualDom_attribute('class'); +var $elm$svg$Svg$Attributes$d = _VirtualDom_attribute('d'); +var $elm$core$String$fromFloat = _String_fromNumber; +var $author$project$Util$ff = $elm$core$String$fromFloat; +var $author$project$App$d_for_path = A2( + $elm$core$Basics$composeR, + $elm$core$List$indexedMap( + F2( + function (i, _v0) { + var x = _v0.a; + var y = _v0.b; + return ((!i) ? 'M' : 'L') + (' ' + ($author$project$Util$ff(x) + (' ' + $author$project$Util$ff(y)))); + })), + $elm$core$String$join(' ')); +var $author$project$App$decode_event_vector = function (fn) { + return A2( + $elm$json$Json$Decode$map, + fn, + A2($elm$json$Json$Decode$field, 'detail', $author$project$App$decode_vector)); +}; +var $elm$html$Html$div = _VirtualDom_node('div'); +var $author$project$App$inverse_triangle = function (k) { + return $elm$core$Basics$floor( + ($elm$core$Basics$sqrt( + ($author$project$Util$tf(k) * 8) + 1) / 2) - 0.5); +}; +var $author$project$App$fan = function (n) { + var r = $author$project$App$inverse_triangle(n); + var t = ((r * (r + 1)) / 2) | 0; + var m = n - t; + var dy = 0.5; + var dx = 2; + return _Utils_Tuple2( + (((-dx) * $author$project$Util$tf(r)) / 2) + (dx * $author$project$Util$tf(m)), + (-dy) * $author$project$Util$tf(r)); +}; +var $author$project$Util$fi = $elm$core$String$fromInt; +var $elm$html$Html$fieldset = _VirtualDom_node('fieldset'); +var $elm$svg$Svg$Attributes$fill = _VirtualDom_attribute('fill'); +var $elm$svg$Svg$Attributes$fillOpacity = _VirtualDom_attribute('fill-opacity'); +var $elm$svg$Svg$Attributes$fontSize = _VirtualDom_attribute('font-size'); +var $elm$core$Dict$Black = {$: 'Black'}; +var $elm$core$Dict$RBNode_elm_builtin = F5( + function (a, b, c, d, e) { + return {$: 'RBNode_elm_builtin', a: a, b: b, c: c, d: d, e: e}; + }); +var $elm$core$Dict$Red = {$: 'Red'}; +var $elm$core$Dict$balance = F5( + function (color, key, value, left, right) { + if ((right.$ === 'RBNode_elm_builtin') && (right.a.$ === 'Red')) { + var _v1 = right.a; + var rK = right.b; + var rV = right.c; + var rLeft = right.d; + var rRight = right.e; + if ((left.$ === 'RBNode_elm_builtin') && (left.a.$ === 'Red')) { + var _v3 = left.a; + var lK = left.b; + var lV = left.c; + var lLeft = left.d; + var lRight = left.e; + return A5( + $elm$core$Dict$RBNode_elm_builtin, + $elm$core$Dict$Red, + key, + value, + A5($elm$core$Dict$RBNode_elm_builtin, $elm$core$Dict$Black, lK, lV, lLeft, lRight), + A5($elm$core$Dict$RBNode_elm_builtin, $elm$core$Dict$Black, rK, rV, rLeft, rRight)); + } else { + return A5( + $elm$core$Dict$RBNode_elm_builtin, + color, + rK, + rV, + A5($elm$core$Dict$RBNode_elm_builtin, $elm$core$Dict$Red, key, value, left, rLeft), + rRight); + } + } else { + if ((((left.$ === 'RBNode_elm_builtin') && (left.a.$ === 'Red')) && (left.d.$ === 'RBNode_elm_builtin')) && (left.d.a.$ === 'Red')) { + var _v5 = left.a; + var lK = left.b; + var lV = left.c; + var _v6 = left.d; + var _v7 = _v6.a; + var llK = _v6.b; + var llV = _v6.c; + var llLeft = _v6.d; + var llRight = _v6.e; + var lRight = left.e; + return A5( + $elm$core$Dict$RBNode_elm_builtin, + $elm$core$Dict$Red, + lK, + lV, + A5($elm$core$Dict$RBNode_elm_builtin, $elm$core$Dict$Black, llK, llV, llLeft, llRight), + A5($elm$core$Dict$RBNode_elm_builtin, $elm$core$Dict$Black, key, value, lRight, right)); + } else { + return A5($elm$core$Dict$RBNode_elm_builtin, color, key, value, left, right); + } + } + }); +var $elm$core$Dict$insertHelp = F3( + function (key, value, dict) { + if (dict.$ === 'RBEmpty_elm_builtin') { + return A5($elm$core$Dict$RBNode_elm_builtin, $elm$core$Dict$Red, key, value, $elm$core$Dict$RBEmpty_elm_builtin, $elm$core$Dict$RBEmpty_elm_builtin); + } else { + var nColor = dict.a; + var nKey = dict.b; + var nValue = dict.c; + var nLeft = dict.d; + var nRight = dict.e; + var _v1 = A2($elm$core$Basics$compare, key, nKey); + switch (_v1.$) { + case 'LT': + return A5( + $elm$core$Dict$balance, + nColor, + nKey, + nValue, + A3($elm$core$Dict$insertHelp, key, value, nLeft), + nRight); + case 'EQ': + return A5($elm$core$Dict$RBNode_elm_builtin, nColor, nKey, value, nLeft, nRight); + default: + return A5( + $elm$core$Dict$balance, + nColor, + nKey, + nValue, + nLeft, + A3($elm$core$Dict$insertHelp, key, value, nRight)); + } + } + }); +var $elm$core$Dict$insert = F3( + function (key, value, dict) { + var _v0 = A3($elm$core$Dict$insertHelp, key, value, dict); + if ((_v0.$ === 'RBNode_elm_builtin') && (_v0.a.$ === 'Red')) { + var _v1 = _v0.a; + var k = _v0.b; + var v = _v0.c; + var l = _v0.d; + var r = _v0.e; + return A5($elm$core$Dict$RBNode_elm_builtin, $elm$core$Dict$Black, k, v, l, r); + } else { + var x = _v0; + return x; + } + }); +var $elm$core$Dict$fromList = function (assocs) { + return A3( + $elm$core$List$foldl, + F2( + function (_v0, dict) { + var key = _v0.a; + var value = _v0.b; + return A3($elm$core$Dict$insert, key, value, dict); + }), + $elm$core$Dict$empty, + assocs); +}; +var $elm$svg$Svg$g = $elm$svg$Svg$trustedNode('g'); +var $elm$svg$Svg$Attributes$height = _VirtualDom_attribute('height'); +var $elm$svg$Svg$Attributes$dominantBaseline = _VirtualDom_attribute('dominant-baseline'); +var $elm$virtual_dom$VirtualDom$text = _VirtualDom_text; +var $elm$svg$Svg$text = $elm$virtual_dom$VirtualDom$text; +var $elm$svg$Svg$Attributes$textAnchor = _VirtualDom_attribute('text-anchor'); +var $elm$svg$Svg$text_ = $elm$svg$Svg$trustedNode('text'); +var $author$project$App$icon = F3( + function (size, text, attrs) { + return A2( + $elm$svg$Svg$text_, + _Utils_ap( + attrs, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$fontSize( + $author$project$Util$ff(size)), + $elm$svg$Svg$Attributes$dominantBaseline('middle'), + $elm$svg$Svg$Attributes$textAnchor('middle') + ])), + _List_fromArray( + [ + $elm$svg$Svg$text(text) + ])); + }); +var $elm$json$Json$Encode$string = _Json_wrap; +var $elm$html$Html$Attributes$stringProperty = F2( + function (key, string) { + return A2( + _VirtualDom_property, + key, + $elm$json$Json$Encode$string(string)); + }); +var $elm$html$Html$Attributes$id = $elm$html$Html$Attributes$stringProperty('id'); +var $elm$svg$Svg$Attributes$id = _VirtualDom_attribute('id'); +var $elm$html$Html$input = _VirtualDom_node('input'); +var $author$project$App$item_icon = function (kind) { + return A3($author$project$App$icon, 2, kind, _List_Nil); +}; +var $elm$html$Html$label = _VirtualDom_node('label'); +var $elm$html$Html$li = _VirtualDom_node('li'); +var $elm$virtual_dom$VirtualDom$Normal = function (a) { + return {$: 'Normal', a: a}; +}; +var $elm$virtual_dom$VirtualDom$on = _VirtualDom_on; +var $elm$html$Html$Events$on = F2( + function (event, decoder) { + return A2( + $elm$virtual_dom$VirtualDom$on, + event, + $elm$virtual_dom$VirtualDom$Normal(decoder)); + }); +var $elm$svg$Svg$Events$on = $elm$html$Html$Events$on; +var $elm$html$Html$Events$onClick = function (msg) { + return A2( + $elm$html$Html$Events$on, + 'click', + $elm$json$Json$Decode$succeed(msg)); +}; +var $elm$json$Json$Decode$oneOf = _Json_oneOf; +var $elm$html$Html$p = _VirtualDom_node('p'); +var $elm$svg$Svg$path = $elm$svg$Svg$trustedNode('path'); +var $author$project$App$point_at_distance_on_path = F2( + function (path, d) { + point_at_distance_on_path: + while (true) { + if (!path.b) { + return $elm$core$Maybe$Nothing; + } else { + if (!path.b.b) { + var a = path.a; + return $elm$core$Maybe$Just(a); + } else { + var a = path.a; + var _v1 = path.b; + var b = _v1.a; + var rest = _v1.b; + var v = A2($author$project$Vector$sub, b, a); + var l = A2($author$project$Vector$distance, a, b); + if (_Utils_cmp(d, l) < 0) { + return $elm$core$Maybe$Just( + A2( + $author$project$Vector$add, + a, + A2($author$project$Vector$smul, d / l, v))); + } else { + var $temp$path = A2($elm$core$List$cons, b, rest), + $temp$d = d - l; + path = $temp$path; + d = $temp$d; + continue point_at_distance_on_path; + } + } + } + } + }); +var $author$project$App$point_at_distance_on_road = F2( + function (road, d) { + var path = road.c; + return A2($author$project$App$point_at_distance_on_path, path, d); + }); +var $elm$svg$Svg$Attributes$r = _VirtualDom_attribute('r'); +var $elm$svg$Svg$rect = $elm$svg$Svg$trustedNode('rect'); +var $author$project$App$stock_counts = function (town) { + return $author$project$App$count_kinds( + A2( + $elm$core$List$map, + function ($) { + return $.kind; + }, + town.items)); +}; +var $elm$svg$Svg$Attributes$stroke = _VirtualDom_attribute('stroke'); +var $elm$svg$Svg$Attributes$strokeDasharray = _VirtualDom_attribute('stroke-dasharray'); +var $elm$svg$Svg$Attributes$strokeWidth = _VirtualDom_attribute('stroke-width'); +var $elm$svg$Svg$svg = $elm$svg$Svg$trustedNode('svg'); +var $elm$html$Html$text = $elm$virtual_dom$VirtualDom$text; +var $elm$svg$Svg$Attributes$transform = _VirtualDom_attribute('transform'); +var $author$project$App$translate_to = function (position) { + return 'translate(' + ($author$project$Util$ff(position.a) + (' ' + ($author$project$Util$ff(position.b) + ' )'))); +}; +var $elm$html$Html$Attributes$type_ = $elm$html$Html$Attributes$stringProperty('type'); +var $elm$html$Html$ul = _VirtualDom_node('ul'); +var $elm$json$Json$Decode$value = _Json_decodeValue; +var $elm$svg$Svg$Attributes$width = _VirtualDom_attribute('width'); +var $elm$svg$Svg$Attributes$x = _VirtualDom_attribute('x'); +var $elm$svg$Svg$Attributes$y = _VirtualDom_attribute('y'); +var $author$project$App$view = function (model) { + var view_town = function (town) { + var view_item = function (_v12) { + var kind = _v12.a; + var count = _v12.b; + var pos = A2($author$project$App$item_position, town, kind); + return A2( + $elm$svg$Svg$g, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$transform( + $author$project$App$translate_to(pos)) + ]), + _List_fromArray( + [ + $author$project$App$item_icon(kind), + A3( + $author$project$App$icon, + 1, + $author$project$Util$fi(count), + _List_fromArray( + [ + $elm$svg$Svg$Attributes$fill('white'), + $elm$svg$Svg$Attributes$stroke('black'), + $elm$svg$Svg$Attributes$strokeWidth('0.2') + ])) + ])); + }; + var num_items = $elm$core$List$length(town.items); + var name = A2( + $elm$svg$Svg$text_, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$textAnchor('middle'), + $elm$svg$Svg$Attributes$fontSize('1'), + $elm$svg$Svg$Attributes$y('-1.5') + ]), + _List_fromArray( + [ + $elm$svg$Svg$text( + $author$project$Util$capitalise(town.name)) + ])); + var item_stocks = $author$project$App$stock_counts(town); + var items = A2( + $elm$svg$Svg$g, + _List_Nil, + A2($elm$core$List$map, view_item, item_stocks)); + var buildings = A2( + $elm$svg$Svg$g, + _List_Nil, + $elm$core$List$reverse( + A2( + $elm$core$List$indexedMap, + F2( + function (i, b) { + var pos = $author$project$App$fan(i); + return A3( + $author$project$App$icon, + 3, + b, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$transform( + $author$project$App$translate_to(pos)) + ])); + }), + $elm$core$List$reverse( + A2( + $elm$core$List$sortBy, + function (b) { + return A2( + $elm$core$Maybe$withDefault, + 0, + A2($elm_community$list_extra$List$Extra$elemIndex, b, $author$project$App$building_kinds)); + }, + town.buildings))))); + return A2( + $elm$svg$Svg$g, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$transform( + $author$project$App$translate_to(town.position)) + ]), + _List_fromArray( + [buildings, name, items])); + }; + var view_road = function (road) { + var from = road.a; + var to = road.b; + var path = road.c; + return A2( + $elm$svg$Svg$g, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$class('road') + ]), + _List_fromArray( + [ + A2( + $elm$svg$Svg$path, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$d( + $author$project$App$d_for_path(path)), + $elm$svg$Svg$Attributes$fill('none'), + $elm$svg$Svg$Attributes$stroke('oklch(0.9 0 0)') + ]), + _List_Nil), + A2( + $elm$svg$Svg$path, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$d( + $author$project$App$d_for_path(path)), + $elm$svg$Svg$Attributes$fill('none'), + $elm$svg$Svg$Attributes$stroke('oklch(1 0 0)'), + $elm$svg$Svg$Attributes$strokeWidth('0.2'), + $elm$svg$Svg$Attributes$strokeDasharray('1 1') + ]), + _List_Nil) + ])); + }; + var view_obstacle = function (obstacle) { + return A2( + $elm$svg$Svg$g, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$transform( + $author$project$App$translate_to(obstacle.position)) + ]), + _List_fromArray( + [ + A2( + $elm$svg$Svg$circle, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$r( + $author$project$Util$ff(obstacle.radius)), + $elm$svg$Svg$Attributes$fill('blue') + ]), + _List_Nil) + ])); + }; + var view_click_mode = function () { + var _v7 = model.click_mode; + switch (_v7.$) { + case 'BlankClick': + return $elm$svg$Svg$text(''); + case 'DragRoad': + var townid = _v7.a; + var path = _v7.b; + var valid = A2($author$project$App$valid_road, model, path); + return view_road( + A3( + $author$project$App$Road, + 0, + 0, + $author$project$App$simplify_road( + $elm$core$List$reverse(path)))); + case 'DragItem': + var item = _v7.a; + var route = _v7.b; + var mroad = _v7.c; + var mcp = function () { + if (mroad.$ === 'Nothing') { + return A2( + $elm$core$Maybe$map, + $elm$core$Tuple$second, + A2($author$project$App$drag_item_position, model, item)); + } else { + var _v10 = mroad.a; + var r = _v10.a; + var from = r.a; + var to = r.b; + var path = r.c; + var d = _v10.b; + return A2($author$project$App$point_at_distance_on_road, r, d); + } + }(); + if (mcp.$ === 'Nothing') { + return $elm$svg$Svg$text(''); + } else { + var cp = mcp.a; + return A2( + $elm$svg$Svg$g, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$transform( + $author$project$App$translate_to(cp)) + ]), + _List_fromArray( + [ + A2( + $elm$svg$Svg$circle, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$r('0.5'), + $elm$svg$Svg$Attributes$fill('lightgrey') + ]), + _List_Nil), + $author$project$App$item_icon(item.kind) + ])); + } + default: + return $elm$svg$Svg$text(''); + } + }(); + var tool_selector = function (_v6) { + var tool = _v6.a; + var label = _v6.b; + return A2( + $elm$html$Html$label, + _List_Nil, + _List_fromArray( + [ + $elm$html$Html$text(label), + A2( + $elm$html$Html$input, + _List_fromArray( + [ + $elm$html$Html$Events$onClick( + $author$project$App$SetTool(tool)), + $elm$html$Html$Attributes$type_('radio'), + $elm$html$Html$Attributes$checked( + _Utils_eq(model.tool, tool)) + ]), + _List_fromArray( + [ + $elm$html$Html$text(label) + ])) + ])); + }; + var selected_town = A2( + $elm$core$Maybe$andThen, + function (i) { + return A2($elm_community$list_extra$List$Extra$getAt, i, model.map.towns); + }, + model.selected_town); + var selected_town_contents = function () { + if (selected_town.$ === 'Nothing') { + return _List_fromArray( + [ + $elm$html$Html$text('') + ]); + } else { + var town = selected_town.a; + var item_stock = $elm$core$Dict$fromList( + $author$project$App$stock_counts(town)); + var building_stock = $elm$core$Dict$fromList( + $author$project$App$building_counts(town)); + var view_recipe = function (recipe) { + var show_count = function (_v5) { + var b = _v5.a; + var n = _v5.b; + return A2( + $elm$core$String$join, + '', + A2($elm$core$List$repeat, n, b)); + }; + var out_items = A2($elm$core$List$map, show_count, recipe.out_items); + var out_buildings = A2($elm$core$List$map, show_count, recipe.out_buildings); + var in_item_stocks = A2( + $elm$core$List$map, + function (_v4) { + var b = _v4.a; + var n = _v4.b; + return _Utils_Tuple3( + b, + n, + A2( + $elm$core$Maybe$withDefault, + 0, + A2($elm$core$Dict$get, b, item_stock))); + }, + recipe.in_items); + var in_building_stocks = A2( + $elm$core$List$map, + function (_v3) { + var b = _v3.a; + var n = _v3.b; + return _Utils_Tuple3( + b, + n, + A2( + $elm$core$Maybe$withDefault, + 0, + A2($elm$core$Dict$get, b, building_stock))); + }, + recipe.in_buildings); + var first_two = function (_v2) { + var a = _v2.a; + var b = _v2.b; + var c = _v2.c; + return _Utils_Tuple2(a, b); + }; + var in_buildings = A2( + $elm$core$List$map, + A2($elm$core$Basics$composeR, first_two, show_count), + in_building_stocks); + var in_items = A2( + $elm$core$List$map, + A2($elm$core$Basics$composeR, first_two, show_count), + in_item_stocks); + return A2( + $elm$html$Html$li, + _List_fromArray( + [ + $elm$html$Html$Events$onClick( + A2($author$project$App$ApplyRecipe, town.id, recipe)) + ]), + _List_fromArray( + [ + $elm$html$Html$text( + A2($elm$core$String$join, ' ', in_buildings)), + $elm$html$Html$text( + A2($elm$core$String$join, ' ', in_items)), + $elm$html$Html$text(' → '), + $elm$html$Html$text( + A2($elm$core$String$join, ' ', out_buildings)), + $elm$html$Html$text( + A2($elm$core$String$join, ' ', out_items)) + ])); + }; + var available_recipes = A2( + $elm$core$List$map, + view_recipe, + A2( + $elm$core$List$filter, + $author$project$App$can_afford_recipe(town), + $author$project$App$recipes)); + return _List_fromArray( + [ + A2( + $elm$html$Html$p, + _List_Nil, + _List_fromArray( + [ + $elm$html$Html$text( + $author$project$Util$capitalise(town.name)) + ])), + A2( + $elm$html$Html$ul, + _List_fromArray( + [ + $elm$html$Html$Attributes$id('recipe-list') + ]), + available_recipes) + ]); + } + }(); + var status_bar = A2( + $elm$html$Html$fieldset, + _List_fromArray( + [ + $elm$html$Html$Attributes$id('status-bar') + ]), + function () { + var _v0 = model.click_mode; + switch (_v0.$) { + case 'DragRoad': + var townid = _v0.a; + var path = _v0.b; + var cost = $author$project$App$road_cost(path); + return _List_fromArray( + [ + $elm$html$Html$text( + 'Building road would cost ' + ($author$project$Util$fi(cost) + '🪨')) + ]); + case 'DragItem': + var item = _v0.a; + return _List_fromArray( + [ + $elm$html$Html$text('Moving ' + item.kind) + ]); + case 'BlankClick': + return selected_town_contents; + default: + var v = _v0.a; + return _List_fromArray( + [ + $elm$html$Html$text('') + ]); + } + }()); + var p2 = _Utils_Tuple2(-15, 0); + var p1 = _Utils_Tuple2(12, 3); + return { + body: _List_fromArray( + [ + A2( + $elm$svg$Svg$svg, + _List_fromArray( + [ + A2( + $elm$svg$Svg$Events$on, + 'svgmove', + $author$project$App$decode_event_vector($author$project$App$SetPosition)), + A2( + $elm$svg$Svg$Events$on, + 'mousedown', + $elm$json$Json$Decode$succeed($author$project$App$PointerDown)), + A2( + $elm$svg$Svg$Events$on, + 'svgtouchstart', + $elm$json$Json$Decode$oneOf( + _List_fromArray( + [ + $author$project$App$decode_touch_vector($author$project$App$TouchStart), + A2($elm$json$Json$Decode$map, $author$project$App$BadValue, $elm$json$Json$Decode$value) + ]))), + A2( + $elm$svg$Svg$Events$on, + 'mouseup', + $elm$json$Json$Decode$succeed($author$project$App$PointerUp)), + A2( + $elm$svg$Svg$Events$on, + 'svgtouchend', + $elm$json$Json$Decode$succeed($author$project$App$TouchEnd)), + A2($elm$html$Html$Attributes$attribute, 'viewBox', '-15 -15 30 30') + ]), + _List_fromArray( + [ + A2( + $elm$svg$Svg$g, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$id('map'), + $elm$svg$Svg$Attributes$transform( + $author$project$App$translate_to(model.camera.pan)) + ]), + _List_fromArray( + [ + A2( + $elm$svg$Svg$rect, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$x('-1000'), + $elm$svg$Svg$Attributes$y('-1000'), + $elm$svg$Svg$Attributes$width('2000'), + $elm$svg$Svg$Attributes$height('2000'), + $elm$svg$Svg$Attributes$fill('hsl(120,80%,70%)') + ]), + _List_Nil), + A2( + $elm$svg$Svg$g, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$id('obstacle-outlines') + ]), + A2($elm$core$List$map, view_obstacle, model.map.obstacles)), + A2( + $elm$svg$Svg$g, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$id('obstacles') + ]), + A2($elm$core$List$map, view_obstacle, model.map.obstacles)), + A2( + $elm$svg$Svg$g, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$id('roads') + ]), + A2($elm$core$List$map, view_road, model.map.roads)), + A2( + $elm$svg$Svg$g, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$id('towns') + ]), + A2($elm$core$List$map, view_town, model.map.towns)), + view_click_mode + ])), + A2( + $elm$svg$Svg$rect, + _List_fromArray( + [ + $elm$svg$Svg$Attributes$fillOpacity('0.0001'), + $elm$svg$Svg$Attributes$x('-10000'), + $elm$svg$Svg$Attributes$y('-10000'), + $elm$svg$Svg$Attributes$width('20000'), + $elm$svg$Svg$Attributes$height('20000') + ]), + _List_Nil) + ])), + A2( + $elm$html$Html$div, + _List_fromArray( + [ + $elm$html$Html$Attributes$id('controls') + ]), + _List_fromArray( + [ + status_bar, + A2( + $elm$html$Html$button, + _List_fromArray( + [ + $elm$html$Html$Events$onClick($author$project$App$EndTurn) + ]), + _List_fromArray( + [ + $elm$html$Html$text('End turn') + ])) + ])) + ]), + title: 'Hey' + }; +}; +var $author$project$App$main = $elm$browser$Browser$document( + {init: $author$project$App$init, subscriptions: $author$project$App$subscriptions, update: $author$project$App$update, view: $author$project$App$view}); +_Platform_export({'App':{'init':$author$project$App$main( + $elm$json$Json$Decode$succeed(_Utils_Tuple0))(0)}});}(this)); \ No newline at end of file diff --git a/elm.json b/elm.json new file mode 100644 index 0000000..97392e3 --- /dev/null +++ b/elm.json @@ -0,0 +1,29 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/browser": "1.0.2", + "elm/core": "1.0.5", + "elm/html": "1.0.0", + "elm/json": "1.1.3", + "elm/parser": "1.1.0", + "elm/random": "1.0.0", + "elm/svg": "1.0.1", + "elm-community/list-extra": "8.7.0", + "elm-community/random-extra": "3.2.0" + }, + "indirect": { + "elm/time": "1.0.0", + "elm/url": "1.0.0", + "elm/virtual-dom": "1.0.3" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..71bc450 --- /dev/null +++ b/index.html @@ -0,0 +1,23 @@ + + + + + + Elm app by clp + + + + +
+

Elm app by clp

+
+
+

This is an app which will either load succesfully, and you'll wonder whether you saw this text at all, or fail ignominiously, showing you only this text.

+

On balance of probabilities: I'm sorry I couldn't be bothered to make this work for you.

+
+ + + + + + \ No newline at end of file diff --git a/load-app.js b/load-app.js new file mode 100644 index 0000000..d76cd9a --- /dev/null +++ b/load-app.js @@ -0,0 +1,11 @@ +import show_error from './show-error.mjs'; +import './svg-events.mjs'; +async function init_app() { + const compilation_error = await show_error; + if(compilation_error) { + return; + } + const app = Elm.App.init({node: document.body, flags: {}}); +} + +init_app(); \ No newline at end of file diff --git a/show-error.mjs b/show-error.mjs new file mode 100644 index 0000000..b2c4086 --- /dev/null +++ b/show-error.mjs @@ -0,0 +1,22 @@ +export default fetch('/error.txt').then(r=>{ + if(r.ok) { + return r.text(); + } else { + throw(''); + } +}).then(text => { + if(!text) { + return false; + } + document.body.innerHTML = ''; + document.body.classList.add('compilation-error'); + const error_show = document.createElement('pre'); + error_show.setAttribute('id','build-error'); + error_show.style.background = 'black'; + error_show.style.color = 'white'; + error_show.style.padding = '1em'; + error_show.style['font-size'] = '16px'; + error_show.textContent = text; + document.body.appendChild(error_show); + return true; +}).catch(e => false); \ No newline at end of file diff --git a/src/App.elm b/src/App.elm new file mode 100644 index 0000000..b1401bf --- /dev/null +++ b/src/App.elm @@ -0,0 +1,1184 @@ +module App exposing (..) + +import Browser +import Dict exposing (Dict) +import Html as H exposing (Html) +import Html.Attributes as HA +import Html.Events as HE +import Json.Decode as JD +import List.Extra as LE +import Parser exposing ((|=), (|.), Parser) +import Random as R +import Random.Extra as RE +import Set +import Svg +import Svg.Attributes as SA +import Svg.Events as SE +import Tuple exposing (first, second, pair, mapSecond) +import Util exposing (..) +import Vector exposing (..) + + +recipes : List Recipe +recipes = List.filterMap (Parser.run parse_recipe >> Result.toMaybe) + [ "⛺1 🧍1🌲1🌿1 🛖 🧍1" + , ". 🧍1🌲1 ⛺1 🧍1" + , ". 🧍1🌲1 . 🧍1🔥1" + , "🛖1 🧍1🪨1🔥1 🛖 🧍1🧱" + , "⛺1 🧍1🧱3🌲2 🏠1 🧍1" + , "🏠3 . 🏘️1 ." + , "🏠1 🍞3 . 🧍1" + , ". 🧍1 . 🧍1🪨1" + , ". 🧍1🌲1 . 🧍1🌱2" + , ". 🌱1 . 🌲1" + , ". 🔥1🌱1 . 🌿1" + , ". 🔥1🌿1 . 🍞1" + ] + +item_kinds = + [ "🌲" + , "🌱" + , "🌿" + , "🪨" + , "🧱" + , "🔥" + , "🧍" + , "🍞" + ] + +building_kinds = + [ "⛺" + , "🛖" + , "🏠" + ] + +main = Browser.document + { init = init + , update = update + , subscriptions = subscriptions + , view = view + } + +type alias TownId = Int + +type alias Path = List Vector + +type ClickMode + = BlankClick + | DragRoad TownId (Path) + | DragItem Item (List TownId) (Maybe (Road, Float)) + | PanCamera Vector + +type Tool + = RoadTool + | MoveItemTool + | MineTool + +type alias Model = + { pointer : Vector + , click_mode : ClickMode + , tool : Tool + , map : Map + , selected_town : Maybe TownId + , debug_log : List String + , camera : Camera + } + +type alias Camera = + { pan : Vector + , zoom : Float + } + +init_camera = + { pan = (0,0) + , zoom = 1 + } + +type Road = Road TownId TownId (Path) + +type alias Obstacle = + { position : Vector + , radius : Float + } + +type alias ItemKind = String + +type alias Item = + { town : TownId + , kind : ItemKind + } + +type alias BuildingKind = String + +type alias Recipe = + { in_buildings : List (BuildingKind,Int) + , in_items : List (ItemKind,Int) + , out_buildings : List (BuildingKind,Int) + , out_items : List (ItemKind,Int) + } + +type alias Town = + { position : Vector + , id : TownId + , items : List Item + , buildings : List BuildingKind + , name : String + } + +type alias Map = + { towns : List Town + , obstacles : List Obstacle + , roads : List Road + } + +parse_symbol_list : Parser (List (String,Int)) +parse_symbol_list = + Parser.loop + [] + (\l -> + Parser.oneOf + [ Parser.succeed + (\(symbol,count) -> Parser.Loop (if symbol=="." then l else (symbol,count)::l)) + |= ( Parser.succeed pair + |= Parser.variable + { start = \c -> not (Char.isDigit c || c == ' ') + , inner = \c -> not (Char.isDigit c || c == ' ') + , reserved = Set.empty + } + |= Parser.oneOf [ Parser.int, Parser.succeed 1 ] + ) + , Parser.succeed () |> Parser.map (\_ -> Parser.Done (List.reverse l)) + ] + ) + +parse_recipe : Parser Recipe +parse_recipe + = Parser.succeed Recipe + |= parse_symbol_list + |. Parser.keyword " " + |. Parser.spaces + |= parse_symbol_list + |. Parser.keyword " " + |. Parser.spaces + |= parse_symbol_list + |. Parser.keyword " " + |. Parser.spaces + |= parse_symbol_list + + +blank_map = + { towns = [] + , obstacles = [] + , roads = [] + } + +init_model = + { pointer = (0,0) + , click_mode = BlankClick + , tool = RoadTool + , map = blank_map + , selected_town = Nothing + , debug_log = [] + , camera = init_camera + } + +type Msg + = SetPosition Vector + | PointerDown + | PointerUp + | TouchStart Vector + | TouchEnd + | SetTool Tool + | SetMap Map + | ApplyRecipe TownId Recipe + | EndTurn + | BadValue JD.Value + +init : () -> (Model, Cmd Msg) +init _ = (init_model, R.generate SetMap map_generator) + +debug : String -> Model -> Model +debug msg model = { model | debug_log = msg::model.debug_log } + +nocmd model = (model, Cmd.none) + +decode_vector : JD.Decoder Vector +decode_vector = JD.map2 pair (JD.field "x" JD.float) (JD.field "y" JD.float) + +decode_event_vector : (Vector -> a) -> JD.Decoder a +decode_event_vector fn = + JD.map fn (JD.field "detail" decode_vector) + +decode_touch_vector : (Vector -> a) -> JD.Decoder a +decode_touch_vector fn = + JD.map fn (JD.at ["detail", "0", "position"] decode_vector) + +poisson : Float -> R.Generator Int +poisson lambda = + let + l = e ^ (-lambda) + + step k p = + R.float 0 1 + |> R.andThen + (\u -> + let + np = p * u + in + if np <= l then R.constant (k-1) else step (k+1) np + ) + in + step 0 1 + +projected_pointer : Model -> Vector +projected_pointer model = sub model.pointer model.camera.pan |> smul model.camera.zoom + +get_town : Model -> TownId -> Maybe Town +get_town model i = LE.getAt i model.map.towns + +next_turn : Map -> R.Generator Map +next_turn original_map = + let + turn_town : Town -> R.Generator Town + turn_town town = + let + num_items = List.length town.items + max_items = 3 + rate = 0.9 + + num_new_items : R.Generator Int + num_new_items = poisson rate |> R.map (min (max_items - num_items)) + + random_item_kinds = + [ "🌲" + , "🌿" + ] + + (k1, rest_kinds) = case random_item_kinds of + [] -> ("",[]) + a::rest -> (a,rest) + + new_item : R.Generator Item + new_item = + R.map2 Item + (R.constant town.id) + (R.uniform k1 rest_kinds) + + new_items : R.Generator (List Item) + new_items = num_new_items |> R.andThen (\n -> R.list n new_item) + + add_new_items t = new_items |> R.map (\items -> { t | items = items++t.items }) + + available_recipes : List Recipe + available_recipes = + recipes + |> List.filter (can_afford_recipe town) + in + R.constant town + |> R.andThen add_new_items + + turn_towns map = + RE.sequence (List.map turn_town map.towns) + |> R.map (\towns -> { map | towns = towns }) + in + R.constant original_map + |> R.andThen turn_towns + +easy_uniform : a -> List a -> R.Generator a +easy_uniform never options = case options of + [] -> R.constant never + a::rest -> R.uniform a rest + +random_name : R.Generator String +random_name = + let + vowels = ["a","e","i","o","u"] + consonants = ["b","c","d","g","m","n","p","r","s","t","ch","th","sh"] + + uniform_string = easy_uniform "" + + random_syllable = R.map2 (++) (uniform_string consonants) (uniform_string vowels) + in + R.list 3 random_syllable + |> R.map (String.join "") + +map_generator : R.Generator Map +map_generator = + let + random_position : R.Generator Vector + random_position = R.map2 pair (R.float -20 20) (R.float -20 20) + + random_town : R.Generator Town + random_town = + R.map2 (\p name -> { position = p, id = 0, items = [], buildings = ["⛺"], name = name }) + random_position + random_name + + random_obstacle = + R.map2 (\p size -> { position = p, radius = size }) + random_position + (R.float (2^2) (6^2) |> R.map sqrt) + + generate_obstacles map = + R.list 20 random_obstacle + |> R.map (\o -> { map | obstacles = o }) + + generate_towns : Map -> R.Generator Map + generate_towns map = + R.list 10 random_town + |> R.map (List.indexedMap (\i t -> { t | id = i })) + |> R.map (distribute_towns map.obstacles) + |> R.map (\t -> { map | towns = t }) + + add_to_random_town : ItemKind -> Map -> R.Generator Map + add_to_random_town kind map = + case map.towns of + [] -> R.constant map + t1::tothers -> + let + rtown = R.uniform t1 tothers + in + rtown + |> R.map (\town -> { map | towns = LE.setIf (.id >> (==) town.id) { town | items = ({ kind = kind, town = town.id }::town.items) } map.towns }) + + in + R.constant blank_map + |> R.andThen generate_obstacles + |> R.andThen generate_towns + |> R.andThen (add_to_random_town "🧍") + |> R.andThen (add_to_random_town "🌲") + +add_item : Model -> R.Generator (Maybe TownId) +add_item model = case model.map.towns of + [] -> R.constant Nothing + a::rest -> R.uniform a rest |> R.map (.id >> Just) + +fract : Float -> (Int,Float) +fract x = (floor x, x - (tf (floor x))) + +total_length points = List.map2 (\v1 v2 -> distance v1 v2) points (List.drop 1 points) |> List.sum + +simplify_path : Float -> Path -> Path +simplify_path step points = + let + simplify_middle : Vector -> (Vector,Float,Path) -> (Vector,Float,Path) + simplify_middle p (last,r,opoints) = + let + v = sub p last + d = len v + n = normalise v + (steps,nr) = fract ((r + d) / step) + nopoints = List.map (\k -> add last (smul (((tf k)-r)*step) n)) (List.range 1 steps) + in + (p,nr,opoints ++ nopoints) + in + case (points, List.reverse points) of + (start::rest, end::_) -> start::(List.foldl simplify_middle (start,0,[]) points |> \(_,_,opoints) -> opoints)++[end] + _ -> [] + +simplify_road = simplify_path 1 + +set_pointer pos model = { model | pointer = pos } + +update_click_mode : Model -> Model +update_click_mode model = + let + pointer = projected_pointer model + + mode = case model.click_mode of + BlankClick -> BlankClick + + DragRoad i path -> DragRoad i (pointer::path) + + PanCamera v -> PanCamera model.pointer + + DragItem item route mroad -> + case mroad of + Nothing -> + let + mcp = drag_item_position model item + mt = get_town model item.town + nmroad = + case mcp of + Nothing -> Nothing + Just (Road _ _ path as r,v) -> + let + md = Maybe.map (.position >> distance v) mt + dr = distance_of_point_on_road r v + total = total_length path + in + Maybe.map2 pair mt md + |> Maybe.andThen + (\(t,d) -> + if dr > 1 && dr < total - 1 then + (Just (r, dr)) + else + Nothing + ) + nroute = case nmroad of + Nothing -> route + Just (Road from to _, _) -> case route of + a::b::rest -> + if a==item.town && ((a==from && b==to) || (a==to &&b==from)) then + b::rest + else + route + _ -> route + + in + DragItem item nroute nmroad + Just (Road from to path as r,d) -> + let + mt1 = get_town model from + mt2 = get_town model to + mcp = closest_point_to_road r pointer + mclosest = + [from,to] + |> List.filterMap (get_town model >> Maybe.map2 (\cp t -> (t,distance cp t.position)) mcp) + |> List.sortBy second + |> List.head + nd = Maybe.map (distance_of_point_on_road r) mcp |> Maybe.withDefault d + max_move = 3 + nnd = d + (clamp (-max_move) max_move (nd-d)) + in + case mclosest of + Nothing -> DragItem item route (Just (r,nnd)) + Just (t,td) -> if td < 1 then DragItem {item | town = t.id } (if List.head route == Just t.id then route else t.id::route) Nothing else DragItem item route (Just (r,nnd)) + in + case model.click_mode of + PanCamera p1 -> + let + d = sub model.pointer p1 |> smul model.camera.zoom + + ncamera = + { pan = add d model.camera.pan + , zoom = model.camera.zoom + } + in + { model | click_mode = mode, camera = ncamera } + + _ -> { model | click_mode = mode } + +update_map : (Map -> Map) -> Model -> Model +update_map fn model = { model | map = fn model.map } + +update_town : (Town -> Town) -> TownId -> Model -> Model +update_town fn townid = update_map (\map -> { map | towns = LE.updateIf (.id >> (==) townid) fn map.towns }) + +change_selected_town : Model -> Model +change_selected_town model = + { model | selected_town = select_town model |> Maybe.map (third >> .id) } + +stock_of_item : String -> Town -> Int +stock_of_item kind = .items >> List.filter (.kind >> (==) kind) >> List.length + +spend_buildings : String -> Int -> TownId -> Model -> Model +spend_buildings kind num = + update_town (\town -> { town | buildings = List.foldl (\building (n,o) -> if building == kind && n>0 then (n-1,o) else (n,building::o)) (num,[]) town.buildings |> second }) + +spend_items : String -> Int -> TownId -> Model -> Model +spend_items kind num = + let + q = Debug.log "spend" (kind,num) + in + update_town (\town -> { town | items = List.foldl (\item (n,o) -> if item.kind == kind && n>0 then (n-1,o) else (n,item::o)) (num,[]) town.items |> second }) + +end_touch : Model -> Model +end_touch model = case (Debug.log "end_touch" model.click_mode) of + BlankClick -> model |> change_selected_town + + DragRoad id1 path -> + let + + road = case select_town model of + Nothing -> Err "no town" + + Just (j,d,t) -> + if id1==t.id then + Err "same start and end" + else + Ok <| Road id1 t.id (simplify_road (t.position::path)) + + is_valid rroad = case rroad of + Road _ _ rpath -> if valid_road model rpath then Ok rroad else Err "hits an obstacle" + + cost = road_cost path + + can_afford rroad = case rroad of + Road from to _ -> + let + rocks_from = from |> get_town model |> Maybe.map (stock_of_item "🪨") |> Maybe.withDefault 0 + in + if rocks_from >= cost then + Ok rroad + else + Err "Not enough 🪨" + + result = + road + |> Result.andThen is_valid + |> Result.andThen can_afford + + finish_road m = + case result of + Err _ -> m + Ok rroad -> + m + |> update_map (\map -> { map | roads = rroad::map.roads }) + |> spend_items "🪨" cost id1 + in + model + |> finish_road + |> change_selected_town + + + DragItem item route _ -> + let + q = Debug.log "drop" item + ntowns = LE.updateAt item.town (\t -> { t | items = item::t.items }) model.map.towns + in + { model | selected_town = Just item.town } |> debug (Debug.toString item) |> update_map (\map -> { map | towns = ntowns }) + + PanCamera _ -> model + +set_blank_click : Model -> Model +set_blank_click model = { model | click_mode = BlankClick } + +select_town : Model -> Maybe (Int, Float, Town) +select_town model = closest_within (\t -> 2) .position (projected_pointer model) model.map.towns + +select_item : Model -> Maybe (Item, Int, Vector) +select_item model = + let + items = positioned_items model.map + in + closest_within (\_ -> 1.5) third (projected_pointer model) items + |> Maybe.map third + +roads_at_town : Model -> TownId -> List Road +roads_at_town model id = + model.map.roads + |> List.filter + (\r -> case r of + Road from to _ -> from==id || to==id + ) + +drag_item_position : Model -> Item -> Maybe (Road,Vector) +drag_item_position model item = + let + roads = roads_at_town model item.town + pointer = projected_pointer model + in + List.filterMap (\r -> closest_point_to_road r pointer |> Maybe.map (pair r)) roads + |> List.sortBy (second >> sub pointer >> len) + |> List.head + +oneOfMaybes : List (Maybe a) -> Maybe a +oneOfMaybes maybes = case maybes of + [] -> Nothing + Nothing::rest -> oneOfMaybes rest + (Just a)::rest -> Just a + +positioned_items : Map -> List (Item, Int, Vector) +positioned_items map = + map.towns + |> List.concatMap + (\t -> t.items |> List.indexedMap (\i item -> (item, i, item_position t item.kind |> add t.position))) + +update : Msg -> Model -> (Model, Cmd Msg) +update msg model = case msg of + SetPosition pos -> model |> set_pointer pos |> update_click_mode |> nocmd + + PointerDown -> + let + towns = model.map.towns + + (mode, ntowns) = oneOfMaybes + [ select_item model |> Maybe.map (\(item,i,pos) -> (DragItem item [item.town] Nothing, LE.updateAt item.town (\t -> { t | items = LE.removeAt i t.items }) model.map.towns)) + , select_town model |> Maybe.map (\(i,d,town) -> (DragRoad town.id [town.position], towns)) + ] + |> Maybe.withDefault (PanCamera model.pointer, towns) + + in + case model.click_mode of + BlankClick -> + { model | click_mode = mode} |> debug "PointerDown" |> update_map (\map -> { map | towns = ntowns }) |> nocmd + + _ -> model |> nocmd + + PointerUp -> model |> debug "PointerUp" |> end_touch |> set_blank_click |> nocmd + + TouchStart pos -> + let + q = Debug.log "TouchStart" pos + in + { model | pointer = pos } |> debug "TouchStart" |> update PointerDown + + TouchEnd -> + let + q = Debug.log "TouchEnd" () + in + update PointerUp (model |> debug "TouchEnd") + + SetTool tool -> { model | tool = tool } |> nocmd + + SetMap map -> + let + person_town = + map.towns + |> LE.find (.items >> List.any (.kind >> (==) "🧍")) + + camera = model.camera |> \c -> case person_town of + Just t -> { c | pan = sub (0,0) t.position } + Nothing -> c + in + { model | map = map, camera = camera } |> nocmd + + ApplyRecipe townid recipe -> model |> apply_recipe townid recipe |> nocmd + + EndTurn -> (model, R.generate SetMap (next_turn model.map)) + + BadValue v -> case JD.decodeValue (decode_touch_vector TouchStart) v of + Ok _ -> model |> nocmd + Err err -> + let + q = Debug.log "err" err + in + model |> nocmd + +subscriptions model = Sub.none + +apply_recipe : TownId -> Recipe -> Model -> Model +apply_recipe townid recipe model = case get_town model townid of + Nothing -> model + Just town -> + let + can_afford = can_afford_recipe town recipe + + spent_buildings : Model -> Model + spent_buildings m = + List.foldl + (\(b,c) buildings -> spend_buildings b c townid buildings) + m + recipe.in_buildings + + spent_items : Model -> Model + spent_items m = + List.foldl + (\(b,c) items -> spend_items b c townid items) + m + recipe.in_items + + new_buildings : List BuildingKind + new_buildings = List.concatMap (\(b,c) -> List.repeat c b) recipe.out_buildings + + new_items : List Item + new_items = List.concatMap (\(b,c) -> List.repeat c { town = townid, kind = b }) recipe.out_items + + spent_model = + model + |> spent_buildings + |> spent_items + |> update_town (\t -> { t | buildings = new_buildings++t.buildings, items = new_items++t.items}) townid + + max_items = 500 + + final_items = + get_town spent_model townid + |> Maybe.map (.items >> List.length) + |> Maybe.withDefault 0 + in + if can_afford && final_items <= max_items then + spent_model + else + model + +iterate : (a -> a) -> Int -> a -> a +iterate fn times list = List.foldl (\_ -> fn) list (List.range 1 times) + +iterate_until : Int -> (a -> a) -> (a -> a -> Bool) -> a -> a +iterate_until run fn condition list = + let + nlist = fn list + in + if condition list nlist then nlist else (iterate_until (run + 1) fn condition nlist) + +distribute_dots : Float -> List Obstacle -> Path +distribute_dots min_dist dots = + let + force_for_dot dot = + let + p1 = dot.position + r1 = dot.radius + dot_forces = + dots + |> List.filter ((/=) dot) + |> List.map + (\d2 -> + let + p2 = d2.position + r2 = d2.radius + v = sub p2 p1 + d = (len v) - (min_dist + r1 + r2) + n = normalise v + force_strength = if d < 0 then 0.1 else 0 + in + smul (d*force_strength) n + ) + in + sum dot_forces + + forces = List.map force_for_dot dots + in + List.map2 (\d f -> add d.position f) dots forces + +distribute_towns : List Obstacle -> List Town -> List Town +distribute_towns obstacles original_towns = + let + step towns = + let + town_obstacles : List Obstacle + town_obstacles = List.map (\t -> {position = t.position, radius = 1}) towns + + positions : Path + positions = distribute_dots 5 (town_obstacles ++ obstacles) + in + List.map2 (\t p -> { t | position = p }) towns positions + + stopped_moving otowns ntowns = + List.map2 (\t1 t2 -> distance t1.position t2.position) otowns ntowns + |> List.sum + |> (>) 1 + in + iterate_until 0 step stopped_moving original_towns + +closest_point_to_road : Road -> Vector -> Maybe Vector +closest_point_to_road road p = case road of + Road _ _ path -> + List.map2 pair path (List.drop 1 path) + |> List.map (\segment -> closest_point_on_segment segment p |> second) + |> LE.minimumBy (\cp -> len (sub p cp)) + +point_at_distance_on_road : Road -> Float -> Maybe Vector +point_at_distance_on_road road d = case road of + Road _ _ path -> point_at_distance_on_path path d + +point_at_distance_on_path : Path -> Float -> Maybe Vector +point_at_distance_on_path path d = case path of + [] -> Nothing + a::[] -> Just a + a::b::rest -> + let + v = sub b a + l = distance a b + in + if d < l then Just (add a (smul (d/l) v)) else point_at_distance_on_path (b::rest) (d-l) + +distance_of_point_on_road : Road -> Vector -> Float +distance_of_point_on_road road p = case road of + Road _ _ original_path -> + let + fn d path = case path of + [] -> 0 + a::[] -> d + a::b::rest -> + let + (t,cp) = closest_point_on_segment (a,b) p + dp = distance p cp + l = distance a b + in + if dp < 0.1 then d + t*l else fn (d+l) (b::rest) + in + fn 0 original_path + +d_for_path : Path -> String +d_for_path = + List.indexedMap (\i (x,y) -> (if i==0 then "M" else "L")++" "++(ff x)++" "++(ff y)) + >> String.join " " + +translate_to : Vector -> String +translate_to position = + "translate(" + ++ (ff <| first position) + ++ " " + ++ (ff <| second position) + ++" )" + +path_intersects_obstacle path obstacle = + List.any (distance obstacle.position >> (>) obstacle.radius) path + +valid_road : Model -> Path -> Bool +valid_road model path = + let + map = model.map + + hit_obstacles = + map.obstacles + |> List.filter (path_intersects_obstacle path) + in + hit_obstacles == [] + +road_cost : Path -> Int +road_cost = total_length >> (*) 0.2 >> ceiling + +item_position : Town -> String -> Vector +item_position town kind = + let + i = LE.elemIndex kind item_kinds |> Maybe.withDefault 0 + an = (tf i) / (tf <| List.length item_kinds - 1) * (2*pi/3) + (pi/6) + r = 2 + x = r * (cos an) + y = r * (sin an) + in + (x,y) + +item_icon kind = icon 2 kind [] + +icon : Float -> String -> (List (H.Attribute msg)) -> Svg.Svg msg +icon size text attrs = + Svg.text_ + ( attrs + ++ [ SA.fontSize <| ff size + , SA.dominantBaseline "middle" + , SA.textAnchor "middle" + ] + ) + [ Svg.text text ] + +count_kinds : List comparable -> List (comparable,Int) +count_kinds = + List.sort + >> LE.group + >> List.map (Tuple.mapSecond (List.length >> (+) 1)) + +stock_counts : Town -> List (ItemKind, Int) +stock_counts town = + town.items + |> List.map .kind + |> count_kinds + +building_counts : Town -> List (BuildingKind, Int) +building_counts town = + town.buildings + |> count_kinds + +has_enough : a -> Int -> List a -> Bool +has_enough kind count list = + list + |> List.filter ((==) kind) + |> List.length + |> (<=) count + +has_enough_items : ItemKind -> Int -> Town -> Bool +has_enough_items kind count = + .items + >> List.map .kind + >> has_enough kind count + +has_enough_buildings : BuildingKind -> Int -> Town -> Bool +has_enough_buildings kind count = + .buildings + >> has_enough kind count + +can_afford_recipe : Town -> Recipe -> Bool +can_afford_recipe town recipe = + let + enough_buildings = List.all (\(b,c) -> has_enough_buildings b c town) recipe.in_buildings + enough_items = List.all (\(b,c) -> has_enough_items b c town) recipe.in_items + + in + enough_items && enough_buildings + +phi = (sqrt 5 + 1) / 2 + +inverse_triangle : Int -> Int +inverse_triangle k = + (sqrt ((tf k) * 8 + 1))/2 - 0.5 |> floor + +spiral : Float -> Int -> Vector +spiral scale i = + let + an = (tf i) * phi/4 - phi/2 + r = scale * (tf i) + in + (r * (cos an), r * (sin an)) + +fan : Int -> Vector +fan n = + let + r = inverse_triangle n + t = r*(r+1) // 2 + m = n - t + dx = 2 + dy = 0.5 + in + (-dx*(tf r)/2 + dx*(tf m),-dy*(tf r)) + + +view model = + let + view_town town = + let + num_items = List.length town.items + item_stocks = stock_counts town + view_item (kind, count) = + let + pos = item_position town kind + in + Svg.g + [ SA.transform <| translate_to pos ] + [ item_icon kind + , icon 1 (fi count) + [ SA.fill "white" + , SA.stroke "black" + , SA.strokeWidth "0.2" + ] + ] + items = + item_stocks + |> List.map view_item + |> Svg.g [] + + buildings = + town.buildings + |> List.sortBy (\b -> LE.elemIndex b building_kinds |> Maybe.withDefault 0) + |> List.reverse + |> List.indexedMap + (\i b -> + let + pos = fan i + in + icon 3 b [ SA.transform <| translate_to pos ] + ) + |> List.reverse + |> Svg.g [] + + name = + Svg.text_ + [ SA.textAnchor "middle" + , SA.fontSize "1" + , SA.y "-1.5" + ] + [ Svg.text <| capitalise town.name ] + in + Svg.g + [ SA.transform <| translate_to town.position + ] + [ buildings + , name + , items + ] + + view_road road = case road of + Road from to path -> + Svg.g + [ SA.class "road" ] + [ Svg.path + [ SA.d <| d_for_path <| path + , SA.fill "none" + , SA.stroke "oklch(0.9 0 0)" + ] + [] + , Svg.path + [ SA.d <| d_for_path <| path + , SA.fill "none" + , SA.stroke "oklch(1 0 0)" + , SA.strokeWidth "0.2" + , SA.strokeDasharray "1 1" + ] + [] + ] + + view_obstacle obstacle = + Svg.g + [ SA.transform <| translate_to obstacle.position ] + [ Svg.circle + [ SA.r <| ff obstacle.radius + , SA.fill "blue" + ] + [] + ] + + view_click_mode = case model.click_mode of + BlankClick -> Svg.text "" + + DragRoad townid path -> + let + valid = valid_road model path + in + view_road (Road 0 0 (simplify_road (List.reverse path))) + + DragItem item route mroad -> + let + mcp = case mroad of + Nothing -> drag_item_position model item |> Maybe.map second + Just ((Road from to path) as r, d) -> point_at_distance_on_road r d + in + case mcp of + Nothing -> Svg.text "" + Just cp -> + Svg.g + [ SA.transform <| translate_to cp ] + [ Svg.circle + [ SA.r "0.5" + , SA.fill "lightgrey" + ] + [] + , item_icon item.kind + ] + + PanCamera _ -> Svg.text "" + + p1 = (12,3) + p2 = (-15,0) + + tool_selector (tool,label) = + H.label + [] + [ H.text label + , H.input + [ HE.onClick (SetTool tool) + , HA.type_ "radio" + , HA.checked <| model.tool == tool + ] + [ H.text label ] + ] + + selected_town = + model.selected_town + |> Maybe.andThen (\i -> LE.getAt i model.map.towns) + + selected_town_contents = case selected_town of + Nothing -> [H.text ""] + Just town -> + let + building_stock = Dict.fromList (building_counts town) + item_stock = Dict.fromList (stock_counts town) + + view_recipe recipe = + let + first_two (a,b,c) = (a,b) + + show_count : (String,Int) -> String + show_count (b,n) = List.repeat n b |> String.join "" + + in_building_stocks : List (BuildingKind, Int, Int) + in_building_stocks = + recipe.in_buildings + |> List.map (\(b,n) -> (b, n, Dict.get b building_stock |> Maybe.withDefault 0)) + + in_buildings = + in_building_stocks + |> List.map (first_two >> show_count) + + in_item_stocks = + recipe.in_items + |> List.map (\(b,n) -> (b, n, Dict.get b item_stock |> Maybe.withDefault 0)) + + in_items = + in_item_stocks + |> List.map (first_two >> show_count) + + out_buildings = + recipe.out_buildings + |> List.map (show_count) + + out_items = + recipe.out_items + |> List.map (show_count) + in + H.li + [ HE.onClick (ApplyRecipe town.id recipe)] + [ H.text <| String.join " " in_buildings + , H.text <| String.join " " in_items + , H.text " → " + , H.text <| String.join " " out_buildings + , H.text <| String.join " " out_items + ] + + available_recipes = + recipes + |> List.filter (can_afford_recipe town) + |> List.map view_recipe + in + [ H.p [] [ H.text <| capitalise <| town.name ] + , H.ul + [ HA.id "recipe-list" ] + available_recipes + ] + + status_bar = + H.fieldset + [ HA.id "status-bar" ] + (case model.click_mode of + DragRoad townid path -> + let + cost = road_cost path + in + [ H.text <| "Building road would cost " ++ (fi cost) ++ "🪨" ] + + DragItem item _ _ -> [ H.text <| "Moving " ++ item.kind ] + + BlankClick -> + selected_town_contents + + PanCamera v -> [H.text ""] + ) + + in + { + title = "Hey", + body = + [ Svg.svg + [ SE.on "svgmove" <| decode_event_vector SetPosition + , SE.on "mousedown" <| JD.succeed PointerDown + , SE.on "svgtouchstart" <| JD.oneOf [decode_touch_vector TouchStart, JD.map BadValue JD.value] + , SE.on "mouseup" <| JD.succeed PointerUp + , SE.on "svgtouchend" <| JD.succeed TouchEnd + , HA.attribute "viewBox" "-15 -15 30 30" + ] + [ Svg.g + [ SA.id "map" + , SA.transform <| translate_to model.camera.pan + ] + [ Svg.rect + [ SA.x "-1000" + , SA.y "-1000" + , SA.width "2000" + , SA.height "2000" + , SA.fill "hsl(120,80%,70%)" + ] + [] + , Svg.g + [ SA.id "obstacle-outlines" ] + (List.map view_obstacle model.map.obstacles) + , Svg.g + [ SA.id "obstacles" ] + (List.map view_obstacle model.map.obstacles) + , Svg.g + [ SA.id "roads" ] + (List.map view_road model.map.roads) + , Svg.g + [ SA.id "towns" ] + (List.map view_town model.map.towns) + , view_click_mode + ] + , Svg.rect + [ SA.fillOpacity "0.0001" + , SA.x "-10000" + , SA.y "-10000" + , SA.width "20000" + , SA.height "20000" + ] + + [] + ] + , H.div + [ HA.id "controls" ] + [ status_bar + , H.button + [ HE.onClick EndTurn ] + [ H.text "End turn" ] + ] + ] + } \ No newline at end of file diff --git a/src/Util.elm b/src/Util.elm new file mode 100644 index 0000000..07b85b4 --- /dev/null +++ b/src/Util.elm @@ -0,0 +1,17 @@ +module Util exposing (..) + +fi = String.fromInt +ff = String.fromFloat +tf = toFloat + +pairMap : (a -> b) -> a -> (a,b) +pairMap fn a = (a, fn a) + +third : (a,b,c) -> c +third (a,b,c) = c + +maybeIf : (a -> Bool) -> Maybe a -> Maybe a +maybeIf condition = Maybe.andThen (\a -> if condition a then Just a else Nothing) + +capitalise : String -> String +capitalise str = (String.left 1 str |> String.toUpper) ++ (String.dropLeft 1 str) \ No newline at end of file diff --git a/src/Vector.elm b/src/Vector.elm new file mode 100644 index 0000000..538413e --- /dev/null +++ b/src/Vector.elm @@ -0,0 +1,60 @@ +module Vector exposing (..) + +import Tuple exposing (pair, first, second) +import Util exposing (maybeIf) + +type alias Vector = (Float, Float) + +type alias LineSegment = (Vector, Vector) + +add (x1,y1) (x2,y2) = (x1+x2, y1+y2) +sub (x1,y1) (x2,y2) = (x1-x2, y1-y2) +len (x,y) = sqrt (x*x + y*y) +smul s (x,y) = (s*x, s*y) +distance v1 v2 = sub v1 v2 |> len + +midpoint (x1,y1) (x2,y2) = ((x1+x2)/2, (y1+y2)/2) + +normalise (x,y) = + let + d = len (x,y) + in + (x/d, y/d) + +normal (x,y) = normalise (-y,x) + +dot (x1,y1) (x2,y2) = x1*x2 + y1*y2 + +sum : List Vector -> Vector +sum = List.foldl add (0,0) + +point_line_distance p (p1,p2) = + let + v1 = sub p2 p1 + v2 = sub p p1 + n = normal v1 + d1 = len v1 + alpha = (dot v1 v2) / d1 + d = len (sub p (add p1 (smul alpha v1))) + in + if alpha<0 then len (sub p p1) else if alpha>d1 then len (sub p p2) else d + +closest : (a -> Vector) -> Vector -> List a -> Maybe (Int, Float, a) +closest get_position p1 = List.map (\a -> (a, get_position a |> sub p1 |> len)) >> List.indexedMap (\i (a,d) -> (i,d,a)) >> List.sortBy (\(i,d,a) -> d) >> List.head + +closest_within : (a -> Float) -> (a -> Vector) -> Vector -> List a -> Maybe (Int, Float, a) +closest_within get_limit get_position p1 things = + closest get_position p1 things + |> maybeIf (\(i,d,a) -> d < get_limit a) + +{- The closest point to the given segment. Returns how far along the segment the point is (0 to 1), and the point -} +closest_point_on_segment : LineSegment -> Vector -> (Float,Vector) +closest_point_on_segment (p1,p2) p = + let + v = sub p2 p1 + vp = sub p p1 + l = len v + d = (dot v vp) / ((len v)^2) + t = clamp 0 1 d + in + (d, add p1 (smul t v)) \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..a589637 --- /dev/null +++ b/style.css @@ -0,0 +1,55 @@ +body { + display: grid; + grid-template: + "svg" 1fr + "controls" 10em + ; + height: 100svh; + margin: 0; + user-select: none; + + &.compilation-error { + grid-template: "error" 1fr; + } + + & #debug-log { + background: #f4f4f4; + } + + & svg { + width: 100%; + height: 100%; + + & text { + user-select: none; + paint-order: stroke fill; + stroke-linejoin: round; + stroke-linecap: round; + fill: white; + stroke: black; + stroke-width: 0.2em; + } + + & #obstacle-outlines circle { + filter: blur(0.5px); + } + } + + & #controls { + display: grid; + grid-auto-flow: column; + } + + & .road path { + stroke-linejoin: round; + } + + + & #recipe-list { + list-style: none; + margin: 0; + padding: 0; + max-height: 100%; + overflow: scroll; + } +} \ No newline at end of file diff --git a/svg-events.mjs b/svg-events.mjs new file mode 100644 index 0000000..66b3803 --- /dev/null +++ b/svg-events.mjs @@ -0,0 +1,62 @@ +function getsvg(event) { + let t = event.target; + while(t && t.tagName.toLowerCase()!='svg') { + t = t.parentElement; + } + return t; +} + +function getcoords(event) { + const t = getsvg(event); + const point = t.createSVGPoint() + point.x = event.clientX + point.y = event.clientY + const position = point.matrixTransform(t.getScreenCTM().inverse()) + return position; +} + +var observer = new MutationObserver(function (mutations) { + mutations.forEach(function (mutation) { + if (mutation.type === 'childList') { + Array + .from(mutation.addedNodes) + .forEach(function (node) { + if(node.nodeType != document.ELEMENT_NODE || node.tagName.toLowerCase() !== 'svg') { + return; + } + node.addEventListener('pointermove', function (event) { + const t = getsvg(event); + if(!t) { + return; + } + const position = getcoords(event); + const svgMoveEvent = new CustomEvent('svgmove', { + detail: {x: position.x, y: position.y}, + }); + t.dispatchEvent(svgMoveEvent); + }); + function svg_touch_event(name) { + node.addEventListener(name, function(event) { + const t = getsvg(event); + if(!t) { + return; + } + event.preventDefault(); + //event.stopPropagation(); + const touches = Array.from(event.changedTouches).map(touch => { + const position = getcoords(touch); + return {identifier: touch.identifier, position: position} + }); + const touchEvent = new CustomEvent('svg'+name, { + detail: touches + }); + t.dispatchEvent(touchEvent); + }); + }; + ['touchstart','touchmove','touchend'].forEach(svg_touch_event) + }); + } + }); +}); + +observer.observe(document.body, { childList: true, subtree: true }); \ No newline at end of file