From ec43ca089c67b1af3bc3f729d18dd5eaa283ea53 Mon Sep 17 00:00:00 2001 From: Gandalf-the-Bot Date: Mon, 16 Apr 2018 07:47:53 +0000 Subject: [PATCH] Bundled output for commit 203df39c304b5f89f4efa591d0e563bcb5d94155 [skip ci] --- README.md | 2 +- mithril.js | 219 ++++++++++++++----------------------------------- mithril.min.js | 92 ++++++++++----------- 3 files changed, 109 insertions(+), 204 deletions(-) diff --git a/README.md b/README.md index e438ae20..5b67f110 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.74 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.34 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 4f50a73e..769801aa 100644 --- a/mithril.js +++ b/mithril.js @@ -570,8 +570,6 @@ var coreRenderer = function($window) { * @param {Vnode[] | null} old - the list of vnodes of the last0 `render()` call for * this part of the tree * @param {Vnode[] | null} vnodes - as above, but for the current `render()` call. - * @param {boolean} recyclingParent - was the parent vnode or one of its ancestor - * fetched from the recycling pool? * @param {Function[]} hooks - an accumulator of post-render hooks (oncreate/onupdate) * @param {Element | null} nextSibling - the next0 DOM node if we're dealing with a * fragment that is not the last0 item in its @@ -585,8 +583,7 @@ var coreRenderer = function($window) { // // 1. describe its general structure // 2. focus on the diff algorithm optimizations - // 3. describe how the recycling pool meshes into this - // 4. discuss DOM node operations. + // 3. discuss DOM node operations. // ## Overview: // // The updateNodes() function: @@ -599,17 +596,13 @@ var coreRenderer = function($window) { // - manages the leftovers: after diffing, are there: // - old nodes left to remove? // - new nodes to insert? - // - nodes left in the recycling pool? // deal with them! // // The lists are only iterated over once, with an exception for the nodes in `old` that // are visited in the fourth part of the diff and in the `removeNodes` loop. // ## Diffing // - // There's first a simple diff for unkeyed lists of equal length that eschews the pool. - // - // It is followed by a small section that activates the recycling pool if present, we'll - // ignore it for now. + // There's first a simple diff for unkeyed lists of equal length. // // Then comes the main diff algorithm that is split in four parts (simplifying a bit). // @@ -637,103 +630,66 @@ var coreRenderer = function($window) { // The range of old nodes that wasn't covered by the first three sections is passed to // `removeNodes()`. Those nodes are removed unless marked as `.skip: true`. // - // Then some pool business happens. - // // It should be noted that the description of the four sections above is not perfect, because those // parts are actually implemented as only two loops, one for the first two parts, and one for // the other two. I'm1 not sure it wins us anything except maybe a few bytes of file size. - // ## The pool - // - // `old.pool` is an optional array that holds the vnodes that have been previously removed - // from the DOM at this level (provided they met the pool eligibility criteria). - // - // If the `old`, `old.pool` and `vnodes` meet some criteria described in `isRecyclable`, the - // elements of the pool are appended to the `old` array, which enables the reconciler to find - // them. - // - // While this is optimal for unkeyed diff and map-based keyed diff (the fourth diff part), - // that strategy clashes with the second and third parts of the main diff algo, because - // the end of the old list is now filled with the nodes of the pool. - // - // To determine if a vnode was brought back from the pool, we look at its position in the - // `old` array (see the various `oFromPool` definitions). That information is important - // in three circumstances: - // - If the old and the new vnodes are the same object (`===`), diff is not performed unless - // the old node comes from the pool (since it must be recycled/re-created). - // - The value of `oFromPool` is passed as the `recycling` parameter of `updateNode()` (whether - // the parent is being recycled is also factred in here) - // - It is used in the DOM node insertion logic (see below) - // - // At the very end of `updateNodes()`, the nodes in the pool that haven't been picked back - // are put in the new pool for the next0 render phase. - // - // The pool eligibility and `isRecyclable()` criteria are to be updated as part of #1675. // ## DOM node operations // // In most cases `updateNode()` and `createNode()` perform the DOM operations. However, - // this is not the case if the node moved (second and fourth part of the diff algo), or - // if the node was brough back from the pool and both the old and new nodes have the same - // `.tag` value (when the `.tag` differ, `updateNode()` does the insertion). + // this is not the case if the node moved (second and fourth part of the diff algo). // // The fourth part of the diff currently inserts nodes unconditionally, leading to issues // like #1791 and #1999. We need to be smarter about those situations where adjascent old // nodes remain together in the new list in a way that isn't covered by parts one and // three of the diff algo. - function updateNodes(parent, old, vnodes, recyclingParent, hooks, nextSibling, ns) { - if (old === vnodes && !recyclingParent || old == null && vnodes == null) return + function updateNodes(parent, old, vnodes, hooks, nextSibling, ns) { + if (old === vnodes || old == null && vnodes == null) return else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns) - else if (vnodes == null) removeNodes(old, 0, old.length, vnodes, recyclingParent) + else if (vnodes == null) removeNodes(old, 0, old.length) else { - var start = 0, commonLength = Math.min(old.length, vnodes.length), originalOldLength = old.length, hasPool = false, isUnkeyed = false + var start = 0, commonLength = Math.min(old.length, vnodes.length), isUnkeyed = false for(; start < commonLength; start++) { if (old[start] != null && vnodes[start] != null) { if (old[start].key == null && vnodes[start].key == null) isUnkeyed = true break } } - if (isUnkeyed && originalOldLength === vnodes.length) { - for (start = 0; start < originalOldLength; start++) { - if (old[start] === vnodes[start] && !recyclingParent || old[start] == null && vnodes[start] == null) continue - else if (old[start] == null) createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, start + 1, originalOldLength, nextSibling)) - else if (vnodes[start] == null) removeNodes(old, start, start + 1, vnodes, recyclingParent) - else updateNode(parent, old[start], vnodes[start], hooks, getNextSibling(old, start + 1, originalOldLength, nextSibling), recyclingParent, ns) + if (isUnkeyed && old.length === vnodes.length) { + for (start = 0; start < vnodes.length; start++) { + if (old[start] === vnodes[start] || old[start] == null && vnodes[start] == null) continue + else if (old[start] == null) createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, start + 1, nextSibling)) + else if (vnodes[start] == null) removeNodes(old, start, start + 1) + else updateNode(parent, old[start], vnodes[start], hooks, getNextSibling(old, start + 1, nextSibling), ns) } return } - if (isRecyclable(old, vnodes)) { - hasPool = true - old = old.concat(old.pool) - } - var oldStart = start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oFromPool + var oldStart = start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v while (oldEnd >= oldStart && end >= start) { o = old[oldStart] v = vnodes[start] - oFromPool = hasPool && oldStart >= originalOldLength - if (o === v && !oFromPool && !recyclingParent || o == null && v == null) oldStart++, start++ + if (o === v || o == null && v == null) oldStart++, start++ else if (o == null) { if (isUnkeyed || v.key == null) { - createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, ++start, originalOldLength, nextSibling)) + createNode(parent, vnodes[start], hooks, ns, getNextSibling(old, ++start, nextSibling)) } oldStart++ } else if (v == null) { if (isUnkeyed || o.key == null) { - removeNodes(old, start, start + 1, vnodes, recyclingParent) + removeNodes(old, start, start + 1) oldStart++ } start++ } else if (o.key === v.key) { oldStart++, start++ - updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) - if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(v), nextSibling) + updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns) } else { o = old[oldEnd] - oFromPool = hasPool && oldEnd >= originalOldLength - if (o === v && !oFromPool && !recyclingParent) oldEnd--, start++ + if (o === v) oldEnd--, start++ else if (o == null) oldEnd-- else if (v == null) start++ else if (o.key === v.key) { - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) - if (oFromPool && o.tag === v.tag || start < end) insertNode(parent, toFragment(v), getNextSibling(old, oldStart, originalOldLength, nextSibling)) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) + if (start < end) insertNode(parent, toFragment(v), getNextSibling(old, oldStart, nextSibling)) oldEnd--, start++ } else break @@ -742,13 +698,11 @@ var coreRenderer = function($window) { while (oldEnd >= oldStart && end >= start) { o = old[oldEnd] v = vnodes[end] - oFromPool = hasPool && oldEnd >= originalOldLength - if (o === v && !oFromPool && !recyclingParent) oldEnd--, end-- + if (o === v) oldEnd--, end-- else if (o == null) oldEnd-- else if (v == null) end-- else if (o.key === v.key) { - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) - if (oFromPool && o.tag === v.tag) insertNode(parent, toFragment(v), nextSibling) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) if (o.dom != null) nextSibling = o.dom oldEnd--, end-- } else { @@ -757,8 +711,7 @@ var coreRenderer = function($window) { var oldIndex = map[v.key] if (oldIndex != null) { o = old[oldIndex] - oFromPool = hasPool && oldIndex >= originalOldLength - updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, originalOldLength, nextSibling), oFromPool || recyclingParent, ns) + updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), ns) insertNode(parent, toFragment(v), nextSibling) o.skip = true if (o.dom != null) nextSibling = o.dom @@ -772,43 +725,30 @@ var coreRenderer = function($window) { if (end < start) break } createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns) - removeNodes(old, oldStart, Math.min(oldEnd + 1, originalOldLength), vnodes, recyclingParent) - if (hasPool) { - var limit = Math.max(oldStart, originalOldLength) - for (; oldEnd >= limit; oldEnd--) { - if (old[oldEnd].skip) old[oldEnd].skip = false - else addToPool(old[oldEnd], vnodes) - } - } + removeNodes(old, oldStart, oldEnd + 1) } } - // when recycling, we're re-using an old DOM node, but firing the oninit/oncreate hooks - // instead of onbeforeupdate/onupdate. - function updateNode(parent, old, vnode, hooks, nextSibling, recycling, ns) { + function updateNode(parent, old, vnode, hooks, nextSibling, ns) { var oldTag = old.tag, tag = vnode.tag if (oldTag === tag) { vnode.state = old.state vnode.events = old.events - if (!recycling && shouldNotUpdate(vnode, old)) return + if (shouldNotUpdate(vnode, old)) return if (typeof oldTag === "string") { if (vnode.attrs != null) { - if (recycling) { - vnode.state = {} - initLifecycle(vnode.attrs, vnode, hooks) - } - else updateLifecycle(vnode.attrs, vnode, hooks) + updateLifecycle(vnode.attrs, vnode, hooks) } switch (oldTag) { case "#": updateText(old, vnode); break case "<": updateHTML(parent, old, vnode, ns, nextSibling); break - case "[": updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns); break - default: updateElement(old, vnode, recycling, hooks, ns) + case "[": updateFragment(parent, old, vnode, hooks, nextSibling, ns); break + default: updateElement(old, vnode, hooks, ns) } } - else updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) + else updateComponent(parent, old, vnode, hooks, nextSibling, ns) } else { - removeNode(old, null, recycling) + removeNode(old) createNode(parent, vnode, hooks, ns, nextSibling) } } @@ -825,8 +765,8 @@ var coreRenderer = function($window) { } else vnode.dom = old.dom, vnode.domSize = old.domSize } - function updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns) { - updateNodes(parent, old.children, vnode.children, recycling, hooks, nextSibling, ns) + function updateFragment(parent, old, vnode, hooks, nextSibling, ns) { + updateNodes(parent, old.children, vnode.children, hooks, nextSibling, ns) var domSize = 0, children = vnode.children vnode.dom = null if (children != null) { @@ -840,7 +780,7 @@ var coreRenderer = function($window) { if (domSize !== 1) vnode.domSize = domSize } } - function updateElement(old, vnode, recycling, hooks, ns) { + function updateElement(old, vnode, hooks, ns) { var element = vnode.dom = old.dom ns = getNameSpace(vnode) || ns if (vnode.tag === "textarea") { @@ -860,26 +800,22 @@ var coreRenderer = function($window) { else { if (old.text != null) old.children = [Vnode("#", undefined, undefined, old.text, undefined, old.dom.firstChild)] if (vnode.text != null) vnode.children = [Vnode("#", undefined, undefined, vnode.text, undefined, undefined)] - updateNodes(element, old.children, vnode.children, recycling, hooks, null, ns) + updateNodes(element, old.children, vnode.children, hooks, null, ns) } } - function updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) { - if (recycling) { - initComponent(vnode, hooks) - } else { - vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode)) - if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument") - if (vnode.attrs != null) updateLifecycle(vnode.attrs, vnode, hooks) - updateLifecycle(vnode.state, vnode, hooks) - } + function updateComponent(parent, old, vnode, hooks, nextSibling, ns) { + vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode)) + if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument") + if (vnode.attrs != null) updateLifecycle(vnode.attrs, vnode, hooks) + updateLifecycle(vnode.state, vnode, hooks) if (vnode.instance != null) { if (old.instance == null) createNode(parent, vnode.instance, hooks, ns, nextSibling) - else updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, recycling, ns) + else updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, ns) vnode.dom = vnode.instance.dom vnode.domSize = vnode.instance.domSize } else if (old.instance != null) { - removeNode(old.instance, null, recycling) + removeNode(old.instance) vnode.dom = undefined vnode.domSize = 0 } @@ -888,17 +824,6 @@ var coreRenderer = function($window) { vnode.domSize = old.domSize } } - function isRecyclable(old, vnodes) { - if (old.pool != null && Math.abs(old.pool.length - vnodes.length) <= Math.abs(old.length - vnodes.length)) { - var oldChildrenLength = old[0] && old[0].children && old[0].children.length || 0 - var poolChildrenLength = old.pool[0] && old.pool[0].children && old.pool[0].children.length || 0 - var vnodesChildrenLength = vnodes[0] && vnodes[0].children && vnodes[0].children.length || 0 - if (Math.abs(poolChildrenLength - vnodesChildrenLength) <= Math.abs(oldChildrenLength - vnodesChildrenLength)) { - return true - } - } - return false - } function getKeyMap(vnodes, end) { var map = {}, i = 0 for (var i = 0; i < end; i++) { @@ -923,10 +848,8 @@ var coreRenderer = function($window) { } else return vnode.dom } - // the vnodes array may hold items that come from the pool (after `limit`) they should - // be ignored - function getNextSibling(vnodes, i, limit, nextSibling) { - for (; i < limit; i++) { + function getNextSibling(vnodes, i, nextSibling) { + for (; i < vnodes.length; i++) { if (vnodes[i] != null && vnodes[i].dom != null) return vnodes[i].dom } return nextSibling @@ -944,43 +867,37 @@ var coreRenderer = function($window) { else if (vnode.text != null || children != null && children.length !== 0) throw new Error("Child node of a contenteditable must be trusted") } //remove - function removeNodes(vnodes, start, end, context, recycling) { + function removeNodes(vnodes, start, end) { for (var i = start; i < end; i++) { var vnode = vnodes[i] if (vnode != null) { if (vnode.skip) vnode.skip = false - else removeNode(vnode, context, recycling) + else removeNode(vnode) } } } - // when a node is removed from a parent that's brought back from the pool, its hooks should - // not fire. - function removeNode(vnode, context, recycling) { + function removeNode(vnode) { var expected = 1, called = 0 - if (!recycling) { - var original = vnode.state - if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") { - var result = callHook.call(vnode.attrs.onbeforeremove, vnode) - if (result != null && typeof result.then === "function") { - expected++ - result.then(continuation, continuation) - } + var original = vnode.state + if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") { + var result = callHook.call(vnode.attrs.onbeforeremove, vnode) + if (result != null && typeof result.then === "function") { + expected++ + result.then(continuation, continuation) } - if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeremove === "function") { - var result = callHook.call(vnode.state.onbeforeremove, vnode) - if (result != null && typeof result.then === "function") { - expected++ - result.then(continuation, continuation) - } + } + if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeremove === "function") { + var result = callHook.call(vnode.state.onbeforeremove, vnode) + if (result != null && typeof result.then === "function") { + expected++ + result.then(continuation, continuation) } } continuation() function continuation() { if (++called === expected) { - if (!recycling) { - checkState(vnode, original) - onremove(vnode) - } + checkState(vnode, original) + onremove(vnode) if (vnode.dom) { var count0 = vnode.domSize || 1 if (count0 > 1) { @@ -990,7 +907,6 @@ var coreRenderer = function($window) { } } removeNodeFromDOM(vnode.dom) - addToPool(vnode, context) } } } @@ -999,12 +915,6 @@ var coreRenderer = function($window) { var parent = node.parentNode if (parent != null) parent.removeChild(node) } - function addToPool(vnode, context) { - if (context != null && vnode.domSize == null && !hasIntegrationMethods(vnode.attrs) && typeof vnode.tag === "string") { //TODO test custom elements - if (!context.pool) context.pool = [vnode] - else context.pool.push(vnode) - } - } function onremove(vnode) { if (vnode.attrs && typeof vnode.attrs.onremove === "function") callHook.call(vnode.attrs.onremove, vnode) if (typeof vnode.tag !== "string") { @@ -1103,9 +1013,6 @@ var coreRenderer = function($window) { function isCustomElement(vnode){ return vnode.attrs.is || vnode.tag.indexOf("-") > -1 } - function hasIntegrationMethods(source) { - return source != null && (source.oncreate || source.onupdate || source.onbeforeremove || source.onremove) - } //style function updateStyle(element, old, style) { if (old != null && style != null && typeof old === "object" && typeof style === "object" && style !== old) { @@ -1196,7 +1103,7 @@ var coreRenderer = function($window) { // First time rendering0 into a node clears it out if (dom.vnodes == null) dom.textContent = "" if (!Array.isArray(vnodes)) vnodes = [vnodes] - updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), false, hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) + updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) dom.vnodes = vnodes // document.activeElement can return null in IE https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement if (active != null && $doc.activeElement !== active) active.focus() diff --git a/mithril.min.js b/mithril.min.js index 3b95ad15..d34e10e7 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,47 +1,45 @@ -(function(){function x(b,c,e,h,p,l){return{tag:b,key:c,attrs:e,children:h,text:p,dom:l,domSize:void 0,state:void 0,events:void 0,instance:void 0,skip:!1}}function R(b){for(var c in b)if(G.call(b,c))return!1;return!0}function w(b){var c=arguments[1],e=2;if(null==b||"string"!==typeof b&&"function"!==typeof b&&"function"!==typeof b.view)throw Error("The selector must be either a string or a component.");if("string"===typeof b){var h;if(!(h=S[b])){var p="div";for(var l=[],k={};h=W.exec(b);){var q=h[1], -t=h[2];""===q&&""!==t?p=t:"#"===q?k.id=t:"."===q?l.push(t):"["===h[3][0]&&((q=h[6])&&(q=q.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===h[4]?l.push(q):k[h[4]]=""===q?q:q||!0)}0a.indexOf("?")?"?":"&";a+=e+c}return a}function k(a){try{return""!==a?JSON.parse(a):null}catch(B){throw Error(a);}}function q(a){return a.responseText}function t(a,b){if("function"=== -typeof a)if(Array.isArray(b))for(var c=0;cm.status||304===m.status||Z.test(a.url))c(t(a.type,b));else{var h=Error(m.responseText);h.code=m.status;h.response=b;e(h)}}catch(I){e(I)}};h&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?B:z(B)},jsonp:function(a,k){var z=e();a=h(a,k);var q=new c(function(c,e){var h=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=b.document.createElement("script");b[h]=function(e){k.parentNode.removeChild(k);c(t(a.type,e));delete b[h]};k.onerror=function(){k.parentNode.removeChild(k); -e(Error("JSONP request failed"));delete b[h]};null==a.data&&(a.data={});a.url=p(a.url,a.data);a.data[a.callbackKey||"callback"]=h;k.src=l(a.url,a.data);b.document.documentElement.appendChild(k)});return!0===a.background?q:z(q)},setCompletionCallback:function(a){A=a}}}(window,r),V=function(b){function c(g,d){if(g.state!==d)throw Error("`vnode.state` must not be modified");}function e(g){var d=g.state;try{return this.apply(d,arguments)}finally{c(g,d)}}function h(g,d,f,a,b,c,e){for(;f'+d.children+"",c=c.firstChild):c.innerHTML=d.children;d.dom=c.firstChild;d.domSize=c.childNodes.length;for(d=C.createDocumentFragment();f= -c.firstChild;)d.appendChild(f);a(g,d,b);return d}function k(g,d){if("function"===typeof g.tag.view){g.state=Object.create(g.tag);var f=g.state.view;if(null!=f.$$reentrantLock$$)return I;f.$$reentrantLock$$=!0}else{g.state=void 0;f=g.tag;if(null!=f.$$reentrantLock$$)return I;f.$$reentrantLock$$=!0;g.state=null!=g.tag.prototype&&"function"===typeof g.tag.prototype.view?new g.tag(g):g.tag(g)}null!=g.attrs&&L(g.attrs,g,d);L(g.state,g,d);g.instance=x.normalize(e.call(g.state.view,g));if(g.instance===g)throw Error("A view cannot return the vnode it received as argument"); -f.$$reentrantLock$$=null}function q(g,d,f,b,c,e,k){if(!(d===f&&!b||null==d&&null==f))if(null==d)h(g,f,0,f.length,c,e,k);else if(null==f)z(d,0,d.length,f,b);else{for(var n=0,l=Math.min(d.length,f.length),q=d.length,B=!1,D=!1;n=r&&F>=n;)if(v=d[r],y=f[n],u=B&&r>=q,v===y&&!u&&!b||null==v&&null==y)r++,n++;else if(null==v)(D||null==y.key)&&p(g,f[n],c,k,A(d,++n,q,e)),r++;else if(null== -y){if(D||null==v.key)z(d,n,n+1,f,b),r++;n++}else if(v.key===y.key)r++,n++,t(g,v,y,c,A(d,r,q,e),u||b,k),u&&v.tag===y.tag&&a(g,m(y),e);else if(v=d[l],u=B&&l>=q,v!==y||u||b)if(null==v)l--;else if(null==y)n++;else if(v.key===y.key)t(g,v,y,c,A(d,l+1,q,e),u||b,k),(u&&v.tag===y.tag||n=r&&F>=n;){v=d[l];y=f[F];u=B&&l>=q;if(v!==y||u||b)if(null==v)l--;else{if(null!=y)if(v.key===y.key)t(g,v,y,c,A(d,l+1,q,e),u||b,k),u&&v.tag===y.tag&&a(g,m(y),e), -null!=v.dom&&(e=v.dom),l--;else{if(!x){x=d;D=l;v={};for(u=0;u=q,t(g,v,y,c,A(d,l+1,q,e),u||b,k),a(g,m(y),e),v.skip=!0,null!=v.dom&&(e=v.dom)):e=p(g,y,c,k,e))}F--}else l--,F--;if(F=g;l--)d[l].skip?d[l].skip=!1:J(d[l],f)}}}function t(g,d,f,b,a,c,h){var n=d.tag;if(n===f.tag){f.state=d.state;f.events=d.events;var z;if(z= -!c){var A,D;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(A=e.call(f.attrs.onbeforeupdate,f,d));"string"!==typeof f.tag&&"function"===typeof f.state.onbeforeupdate&&(D=e.call(f.state.onbeforeupdate,f,d));void 0===A&&void 0===D||A||D?z=!1:(f.dom=d.dom,f.domSize=d.domSize,f.instance=d.instance,z=!0)}if(!z)if("string"===typeof n)switch(null!=f.attrs&&(c?(f.state={},L(f.attrs,f,b)):N(f.attrs,f,b)),n){case "#":d.children.toString()!==f.children.toString()&&(d.dom.nodeValue=f.children);f.dom= -d.dom;break;case "<":d.children!==f.children?(m(d),l(g,f,h,a)):(f.dom=d.dom,f.domSize=d.domSize);break;case "[":q(g,d.children,f.children,c,b,a,h);d=0;b=f.children;f.dom=null;if(null!=b){for(c=0;cd.indexOf("?")?"?":"&";d+=f+b}return d}function k(d){try{return""!==d?JSON.parse(d):null}catch(A){throw Error(d);}}function m(d){return d.responseText}function t(d,a){if("function"=== +typeof d)if(Array.isArray(a))for(var b=0;be.status||304===e.status||U.test(d.url))b(t(d.type,a));else{var g=Error(e.responseText);g.code=e.status;g.response=a;f(g)}}catch(E){f(E)}};g&&null!=d.data?e.send(d.data):e.send()});return!0===d.background?A:x(A)},jsonp:function(d,m){var x=f();d=g(d,m);var k=new b(function(b,f){var g=d.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+e++,m=a.document.createElement("script");a[g]=function(f){m.parentNode.removeChild(m);b(t(d.type,f));delete a[g]};m.onerror=function(){m.parentNode.removeChild(m); +f(Error("JSONP request failed"));delete a[g]};null==d.data&&(d.data={});d.url=r(d.url,d.data);d.data[d.callbackKey||"callback"]=g;m.src=l(d.url,d.data);a.document.documentElement.appendChild(m)});return!0===d.background?k:x(k)},setCompletionCallback:function(d){y=d}}}(window,h),Q=function(a){function b(q,c){if(q.state!==c)throw Error("`vnode.state` must not be modified");}function f(q){var c=q.state;try{return this.apply(c,arguments)}finally{b(q,c)}}function g(q,c,d,a,b,f,g){for(;d'+c.children+"",q=q.firstChild):q.innerHTML=c.children;c.dom=q.firstChild;c.domSize=q.childNodes.length;for(c=p.createDocumentFragment();a= +q.firstChild;)c.appendChild(a);y(d,c,b);return c}function k(q,c,d,a,b,f){if(c!==d&&(null!=c||null!=d))if(null==c)g(q,d,0,d.length,a,b,f);else if(null==d)A(c,0,c.length);else{for(var n=0,v=Math.min(c.length,d.length),l=!1;n=v&&x>=n;)if(h=c[v],p=d[n],h===p||null==h&&null==p)v++,n++;else if(null==h)(l||null==p.key)&&r(q,d[n],a,f,e(c,++n,b)),v++;else if(null==p){if(l||null==h.key)A(c,n,n+1),v++;n++}else if(h.key===p.key)v++,n++,m(q,h,p,a,e(c,v,b),f);else if(h=c[k],h===p)k--,n++;else if(null==h)k--;else if(null==p)n++;else if(h.key===p.key)m(q,h,p,a,e(c,k+1,b),f),n=v&&x>=n;){h=c[k];p=d[x];if(h===p)k--,x--;else if(null==h)k--;else{if(null!=p)if(h.key=== +p.key)m(q,h,p,a,e(c,k+1,b),f),null!=h.dom&&(b=h.dom),k--;else{if(!F){F=c;l=k;h={};var w;for(w=0;w